dubbo:service
、dubbo:reference
、dubbo:consumer
、dubbo:provider
中可以配置布尔类型的 validation 属性,含义是:
是否启用JSR303标准注解验证,如果启用,将根据方法参数上的注解进行校验
JSR303 用于 Bean Validation ,规范地址: https://beanvalidation.org/1.0/spec/ 。
不过现在已经有 JSR380 (Bean Validation 2.0)了,规范地址:https://beanvalidation.org/2.0/ 。
Java Hibernate validator 校验框架的旧版本实现了 JSR303,大版本6 实现了 JSR380 。
从在 dubbo 中的测试效果来看,JSR380 和 JSR303 的实现版本都可以用。
本文示例代码基于 Dubbo:使用 Spring 注解构建 Dubbo 服务 中的示例项目。
项目结构
.
├── README.md
├── build.gradle
├── settings.gradle
├── consumer
│ ├── src
│ └── main
│ ├── java
│ │ └── demo
│ │ └── consumer
│ │ ├── ConsumerMainV1.java
│ │ └── ConsumerMainV2.java
│ └── resources
│ ├── dubbo-consumer.xml
│ ├── dubbo.properties
│ └── log4j.properties
├── contract
│ ├── src
│ └── main
│ └── java
│ └── demo
│ └── contract
│ ├── DemoService.java
│ └── requset
│ └── HiRequest.java
├── provider
│ ├── src
│ │ └── main
│ ├── java
│ │ └── demo
│ │ └── provider
│ │ ├── DemoServiceImpl.java
│ │ └── ProviderMain.java
│ └── resources
│ ├── dubbo-provider.xml
│ ├── dubbo.properties
│ └── log4j.properties
build.gradle 内容如下:
group 'com.example'
version '1.0-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.8
ext {
dubboVersion = '2.7.1'
zookeeperVersion = '3.4.10'
zkclientVersion = '0.10'
junitVersion = '4.12'
}
subprojects {
apply plugin: 'java'
repositories {
maven { url 'https://maven.aliyun.com/repository/public/' }
mavenCentral()
}
// 配置除了 contract 模块之外的所有模块
if (!it.name.endsWith("contract")) {
dependencies {
compile group: 'org.hibernate.validator', name: 'hibernate-validator', version: '6.0.11.Final'
compile group: 'org.glassfish', name: 'javax.el', version: '3.0.1-b09'
}
}
dependencies {
compile group: 'org.projectlombok', name: 'lombok', version: '1.18.0'
}
}
// 配置子项目 contract
project(":contract") {
dependencies {
compile "javax.validation:validation-api:2.0.1.Final"
testCompile "junit:junit:$junitVersion"
}
}
// 配置子项目 consumer
project(":consumer") {
dependencies {
compile project(":contract") // 依赖子项目 contract
compile "org.apache.dubbo:dubbo:$dubboVersion"
compile "org.apache.dubbo:dubbo-dependencies-zookeeper:$dubboVersion"
testCompile "junit:junit:$junitVersion"
}
}
project(":provider") { // 配置子项目 provider
dependencies {
compile project(":contract") // 依赖子项目 contract
compile "org.apache.dubbo:dubbo:$dubboVersion"
compile "org.apache.dubbo:dubbo-dependencies-zookeeper:$dubboVersion"
testCompile "junit:junit:$junitVersion"
}
}
协议定义
contract 中 DemoService 内容如下:
package demo.contract;
import demo.contract.requset.HiRequest;
import javax.validation.constraints.NotBlank;
public interface DemoService {
String sayHello(@NotBlank(message = "name不能为空") String name);
String sayHi(HiRequest request);
}
其中,HiRequest 类内容如下:
package demo.contract.requset;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = false)
public class HiRequest implements Serializable {
@NotBlank(message = "msg不能为空")
private String msg;
}
服务端实现
provider 模块中 DemoServiceImpl 如下:
package demo.provider;
import demo.contract.DemoService;
import demo.contract.requset.HiRequest;
import org.springframework.stereotype.Service;
@Service
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello, " + name;
}
@Override
public String sayHi(HiRequest request) {
return "Hi, " + request.getMsg();
}
}
ProviderMain 内容见源码。
dubbo-provider.xml 内容在下面测试时会给出。
消费端实现
consumer 模块中 ConsumerMainV1 类内容:
package demo.consumer;
import demo.contract.DemoService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource({"dubbo-consumer.xml"})
public class ConsumerMainV1 {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConsumerMainV1.class);
DemoService demoService = ctx.getBean(DemoService.class);
String s = demoService.sayHello("");
System.out.println(s);
}
}
ConsumerMainV2 类:
package demo.consumer;
import demo.contract.DemoService;
import demo.contract.requset.HiRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource({"dubbo-consumer.xml"})
public class ConsumerMainV2 {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConsumerMainV2.class);
DemoService demoService = ctx.getBean(DemoService.class);
HiRequest hiRequest = new HiRequest();
hiRequest.setMsg(" ");
String result = demoService.sayHi(hiRequest);
System.out.println(result);
}
}
测试:消费端校验参数,服务端不校验参数
consumer 模块中的 dubbo-consumer.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="consumer-of-helloworld-app"/>
<dubbo:consumer timeout="5000" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" check="false"/>
<dubbo:reference id="demoService"
interface="demo.contract.DemoService"
check="false"
validation="true"
/>
</beans>
注意,增加了validation="true"
,表示要对参数进行校验。
provider 模块中的 dubbo-provider.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="hello-world-app"></dubbo:application>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="dubbo" port="20881"/>
<dubbo:service interface="demo.contract.DemoService"
class="demo.provider.DemoServiceImpl"
validation="false"
/>
</beans>
运行服务端的 ProviderMain 类,然后测试消费端运行结果。
执行 consumer 中的 ConsumerMainV1 ,会看到以下异常:
ERROR [main] - [DUBBO] Failed to validate service: demo.contract.DemoService, method: sayHello, cause: [ConstraintViolationImpl{interpolatedMessage='name不能为空', propertyPath=sayHelloArgument0, rootBeanClass=class demo.contract.DemoService_SayHelloParameter_java.lang.String, messageTemplate='name不能为空'}], dubbo version: 2.7.1, current host: 127.0.0.1
Exception in thread "main" javax.validation.ConstraintViolationException: Failed to validate service: demo.contract.DemoService, method: sayHello, cause: [ConstraintViolationImpl{interpolatedMessage='name不能为空', propertyPath=sayHelloArgument0, rootBeanClass=class demo.contract.DemoService_SayHelloParameter_java.lang.String, messageTemplate='name不能为空'}]
at org.apache.dubbo.validation.support.jvalidation.JValidator.validate(JValidator.java:276)
at org.apache.dubbo.validation.filter.ValidationFilter.invoke(ValidationFilter.java:85)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:88)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:49)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:54)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)
at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80)
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:242)
at org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:76)
at org.apache.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:57)
at org.apache.dubbo.common.bytecode.proxy0.sayHello(proxy0.java)
at demo.consumer.ConsumerMainV1.main(ConsumerMainV1.java:18)
执行 consumer 中的 ConsumerMainV2 ,会看到以下异常:
ERROR [main] - [DUBBO] Failed to validate service: demo.contract.DemoService, method: sayHi, cause: [ConstraintViolationImpl{interpolatedMessage='msg不能为空', propertyPath=msg, rootBeanClass=class demo.contract.requset.HiRequest, messageTemplate='msg不能为空'}], dubbo version: 2.7.1, current host: 127.0.0.1
Exception in thread "main" javax.validation.ConstraintViolationException: Failed to validate service: demo.contract.DemoService, method: sayHi, cause: [ConstraintViolationImpl{interpolatedMessage='msg不能为空', propertyPath=msg, rootBeanClass=class demo.contract.requset.HiRequest, messageTemplate='msg不能为空'}]
at org.apache.dubbo.validation.support.jvalidation.JValidator.validate(JValidator.java:276)
at org.apache.dubbo.validation.filter.ValidationFilter.invoke(ValidationFilter.java:85)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:88)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:49)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:54)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)
at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80)
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:242)
at org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:76)
at org.apache.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:57)
at org.apache.dubbo.common.bytecode.proxy0.sayHi(proxy0.java)
at demo.consumer.ConsumerMainV2.main(ConsumerMainV2.java:21)
测试:服务端校验参数,消费端不校验参数
这种情况下,消费端的请求会走到服务端,然后服务端会会对参数进行校验。若校验失败,则将失败信息返回给消费端。
consumer 模块中的 dubbo-consumer.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="consumer-of-helloworld-app"/>
<dubbo:consumer timeout="5000" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" check="false"/>
<!--将 validation 设置为 false-->
<dubbo:reference id="demoService"
interface="demo.contract.DemoService"
check="false"
validation="false"
/>
</beans>
provider 模块中的 dubbo-provider.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="hello-world-app"></dubbo:application>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="dubbo" port="20881"/>
<!--将 validation 设置为 true-->
<dubbo:service interface="demo.contract.DemoService"
class="demo.provider.DemoServiceImpl"
validation="true"
/>
</beans>
运行服务端的 ProviderMain 类,然后测试消费端运行结果。
执行 consumer 中的 ConsumerMainV1 ,会看到以下异常:
Exception in thread "main" org.apache.dubbo.rpc.RpcException: Failed to invoke the method sayHello in the service demo.contract.DemoService. Tried 3 times of the providers [127.0.0.1:20881] (1/1) from the registry 127.0.0.1:2181 on the consumer 127.0.0.1 using the dubbo version 2.7.1. Last error is: Failed to invoke remote method: sayHello, provider: dubbo://127.0.0.1:20881/demo.contract.DemoService?anyhost=true&application=consumer-of-helloworld-app&bean.name=demo.contract.DemoService&check=false&class=demo.provider.DemoServiceImpl&default.deprecated=false&default.dynamic=false&default.lazy=false&default.register=true&default.sticky=false&default.timeout=5000&deprecated=false&dubbo=2.0.2&dynamic=false&generic=false&interface=demo.contract.DemoService&lazy=false&methods=sayHello,sayHi&pid=79466&qos.port=33333®ister=true®ister.ip=127.0.0.1&release=2.7.1&remote.application=hello-world-app&remote.timestamp=1557814984617&side=consumer&sticky=false×tamp=1557815109410&validation=false, cause: Failed to send response: Response [id=2, version=2.0.2, status=20, event=false, error=null, result=RpcResult [result=null, exception=javax.validation.ConstraintViolationException: Failed to validate service: demo.contract.DemoService, method: sayHello, cause: [ConstraintViolationImpl{interpolatedMessage='name不能为空', propertyPath=sayHelloArgument0, rootBeanClass=class demo.contract.DemoService_SayHelloParameter_java.lang.String, messageTemplate='name不能为空'}]]], cause: java.lang.RuntimeException: Serialized class demo.contract.DemoService_SayHelloParameter_java.lang.String must implement java.io.Serializable
Java field: private final java.lang.Object org.hibernate.validator.internal.engine.ConstraintViolationImpl.leafBeanInstance
Java field: private final java.util.Set javax.validation.ConstraintViolationException.constraintViolations
java.lang.RuntimeException: Serialized class demo.contract.DemoService_SayHelloParameter_java.lang.String must implement java.io.Serializable
这个错误有点奇怪,先留着。
执行 consumer 中的 ConsumerMainV2 ,会看到以下异常:
Exception in thread "main" org.apache.dubbo.rpc.RpcException: Failed to invoke the method sayHi in the service demo.contract.DemoService. Tried 3 times of the providers [127.0.0.1:20881] (1/1) from the registry 127.0.0.1:2181 on the consumer 127.0.0.1 using the dubbo version 2.7.1. Last error is: Failed to invoke remote method: sayHi, provider: dubbo://127.0.0.1:20881/demo.contract.DemoService?anyhost=true&application=consumer-of-helloworld-app&bean.name=demo.contract.DemoService&check=false&class=demo.provider.DemoServiceImpl&default.deprecated=false&default.dynamic=false&default.lazy=false&default.register=true&default.sticky=false&default.timeout=5000&deprecated=false&dubbo=2.0.2&dynamic=false&generic=false&interface=demo.contract.DemoService&lazy=false&methods=sayHello,sayHi&pid=79488&qos.port=33333®ister=true®ister.ip=127.0.0.1&release=2.7.1&remote.application=hello-world-app&remote.timestamp=1557814984617&side=consumer&sticky=false×tamp=1557815279401&validation=false, cause: com.alibaba.com.caucho.hessian.io.HessianFieldException: org.hibernate.validator.internal.engine.ConstraintViolationImpl.constraintDescriptor: 'org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl' could not be instantiated
com.alibaba.com.caucho.hessian.io.HessianFieldException: org.hibernate.validator.internal.engine.ConstraintViolationImpl.constraintDescriptor: 'org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl' could not be instantiated
这个错误依然很奇怪,原因 dubbo 默认的 Hessian 序列化协议对 hibernate validator 的报错信息序列化有问题,简单说,是 ConstraintDescriptorImpl 没有实现无参构造函数。这个应该是 dubbo 框架本身去解决这个问题,但是目前没有解决。具体可以参考Dubbo使用jsr303框架hibernate-validator遇到的问题 这篇文章中的讨论。
修复服务端参数校验问题
在上面的测试中,我们发现服务端参数校验给出的错误信息很奇怪,Dubbo使用jsr303框架hibernate-validator遇到的问题 给出了原因和解决方案。其中一个解决方案是修改hibernate-validator的原生类,修改Dubbo ValidationFilter,这也是我最终采用的方法
。
修改原生类有很多方法,可以是直接修改源码,之后打包,只给自己的项目用。也可以通过 javaagent 动态添加。
还有一个更简单的解决方案:新建一个 validation filter ,并使用自定义的异常代表参数校验失败。
项目结构:
.
├── README.md
├── settings.gradle
├── build.gradle
├── consumer
│ ├── src
│ └── main
│ ├── java
│ │ └── demo
│ │ └── consumer
│ │ ├── ConsumerMainV1.java
│ │ └── ConsumerMainV2.java
│ └── resources
│ ├── dubbo-consumer.xml
│ ├── dubbo.properties
│ └── log4j.properties
├── contract
│ ├── src
│ └── main
│ └── java
│ └── demo
│ └── contract
│ ├── DemoService.java
│ ├── exception
│ │ └── ParamCheckFailException.java // 新增异常类
│ └── requset
│ └── HiRequest.java
├── provider
├── src
└── main
├── java
│ └── demo
│ └── provider
│ ├── CustomValidationFilter.java // 校验用的 filter
│ ├── DemoServiceImpl.java
│ └── ProviderMain.java
└── resources
├── META-INF
│ └── dubbo
│ └── org.apache.dubbo.rpc.Filter // 定义 filter
├── dubbo-provider.xml
├── dubbo.properties
└── log4j.properties
ParamCheckFailException 异常类:
package demo.contract.exception;
/**
* 参数校验失败异常
*/
public class ParamCheckFailException extends RuntimeException {
public ParamCheckFailException(String msg) {
super(msg);
}
}
CustomValidationFilter 过滤器(改造自 org.apache.dubbo.validation.filter.ValidationFilter):
package demo.provider;
import demo.contract.exception.ParamCheckFailException;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.validation.Validation;
import org.apache.dubbo.validation.Validator;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcResult;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;
@Slf4j
@Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.VALIDATION_KEY, order = 10000)
public class CustomValidationFilter implements Filter {
private Validation validation;
public void setValidation(Validation validation) {
this.validation = validation;
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
if (validation != null && !invocation.getMethodName().startsWith("$")
&& ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.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 (ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
log.info("校验错误详情:{}", constraintViolations);
if (constraintViolations.size() > 0) {
// 不用关心所有的校验失败情况,关心一个就够了
return new RpcResult(new ParamCheckFailException(constraintViolations.iterator().next().getMessage()));
}
throw new ParamCheckFailException("校验失败");
} catch (Throwable t) {
return new RpcResult(t);
}
}
return invoker.invoke(invocation);
}
}
provider 模块中的 META-INF/dubbo/org.apache.dubbo.rpc.Filter
文件内容如下:
customValidation=demo.provider.CustomValidationFilter
在 dubbo-provider.xml 配置过滤器:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="hello-world-app"></dubbo:application>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="dubbo" port="20881"/>
<!--配置过滤器,去掉默认的 validation,增加自定义的 customValidation-->
<dubbo:provider filter="default,-validation,customValidation" />
<dubbo:service interface="demo.contract.DemoService"
class="demo.provider.DemoServiceImpl"
validation="true"
/>
</beans>
测试:
运行 ProviderMain 。
执行 consumer 中的 ConsumerMainV1 ,会看到以下异常:
Exception in thread "main" demo.contract.exception.ParamCheckFailException: name不能为空
at demo.provider.CustomValidationFilter.invoke(CustomValidationFilter.java:47)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:63)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:88)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:54)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:80)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:79)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:137)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:39)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73)
at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:128)
at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:103)
at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:200)
at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:51)
at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
执行 consumer 中的 ConsumerMainV2 ,会看到以下异常:
Exception in thread "main" demo.contract.exception.ParamCheckFailException: msg不能为空
......
......
是在服务端配置参数校验,还是在消费端配置?
服务端必须配置,消费端最好配置。