接上文http://blog.sina.com.cn/s/blog_7d1968e20102ww6x.html
对于java
web应用来说,spring的filter可以拦截web接口调用,但对于dubbo接口,spring的filter就不起作用了。
设想有这样一种场景,comsumer调用了provider的接口方法,comsumer中的异常类型是MyException(checked类型),而provider抛出的是RuntimeException(unchecked类型),所以我们需要在consumer调用provider的实现类方法之前将其拦截,然后调用方法,捕获RuntimeException并将其封装成MyException,然后返回给consumer,此时就需要dubbo的扩展点
一.首先增加dubbo-starter项目下关于filter配置
@Configuration
@ConditionalOnClass({Exporter.class, Invoker.class})
@PropertySource(value =
"classpath:/application.properties")
public class DubboConfiguration {
@Value("${dubbo.application.name}")
private String
applicationName;
@Value("${spring.redis.host}")
private String
logger;
@Value("${dubbo.registr.protocol}")
private String
protocol;
@Value("${dubbo.registry.address}")
private String
registryAddress;
@Value("${dubbo.protocol.name}")
private String
protocolName;
@Value("${dubbo.protocol.port}")
private int
protocolPort;
@Value("${dubbo.provider.timeout}")
private int
timeout;
@Value("${dubbo.provider.retries}")
private int
retries;
@Value("${dubbo.provider.delay}")
private int delay;
@Value("${dubbo.provider.filter}")
private String
providerFilter;
@Bean
public static
AnnotationBean annotationBean(@Value("${dubbo.annotation.package}")
String packageName) {
AnnotationBean annotationBean = new
AnnotationBean();
annotationBean.setPackage(packageName);
return annotationBean;
}
@Bean
public ApplicationConfig
applicationConfig() {
// 当前应用配置
ApplicationConfig applicationConfig = new
ApplicationConfig();
applicationConfig.setName(this.applicationName);
return applicationConfig;
}
@Bean
public RegistryConfig
registryConfig() {
// 连接注册中心配置
RegistryConfig registry = new
RegistryConfig();
registry.setProtocol(protocol);
registry.setAddress(registryAddress);
return registry;
}
@Bean
public ProtocolConfig
protocolConfig() {
// 服务提供者协议配置
ProtocolConfig protocolConfig = new
ProtocolConfig();
protocolConfig.setName(protocolName);
protocolConfig.setPort(protocolPort);
protocolConfig.setThreads(200);
System.out.println("默认protocolConfig:" +
protocolConfig.hashCode());
return protocolConfig;
}
@Bean(name="defaultProvider")
public ProviderConfig
providerConfig(ApplicationConfig applicationConfig, RegistryConfig
registryConfig, ProtocolConfig protocolConfig) {
ProviderConfig providerConfig = new
ProviderConfig();
providerConfig.setTimeout(timeout);
providerConfig.setRetries(retries);
providerConfig.setDelay(delay);
providerConfig.setFilter(providerFilter);
providerConfig.setApplication(applicationConfig);
providerConfig.setRegistry(registryConfig);
providerConfig.setProtocol(protocolConfig);
return providerConfig;
}
public String
getApplicationName() {
return applicationName;
}
public void
setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
public String
getLogger() {
return logger;
}
public void
setLogger(String logger) {
this.logger = logger;
}
public String
getProtocol() {
return protocol;
}
public void
setProtocol(String protocol) {
this.protocol = protocol;
}
public String
getRegistryAddress() {
return registryAddress;
}
public void
setRegistryAddress(String registryAddress) {
this.registryAddress = registryAddress;
}
public String
getProtocolName() {
return protocolName;
}
public void
setProtocolName(String protocolName) {
this.protocolName = protocolName;
}
public int
getProtocolPort() {
return protocolPort;
}
public void
setProtocolPort(int protocolPort) {
this.protocolPort = protocolPort;
}
public int getTimeout()
{
return timeout;
}
public void
setTimeout(int timeout) {
this.timeout = timeout;
}
public int getRetries()
{
return retries;
}
public void
setRetries(int retries) {
this.retries = retries;
}
public int getDelay()
{
return delay;
}
public void setDelay(int
delay) {
this.delay = delay;
}
public String
getProviderFilter() {
return providerFilter;
}
public void
setProviderFilter(String providerFilter) {
this.providerFilter = providerFilter;
}
}
二.
dubbo-provider项目下
1.使用filter和active创建dubbo扩展点的MyExceptionFilter
@Activate(group = Constants.PROVIDER, value =
"exceptionfilter")
public class MyExceptionFilter
implements Filter{
@Override
public
Result invoke(Invoker<?>
invoker, Invocation invocation) throws RpcException {
Result result =
invoker.invoke(invocation);
if(result.hasException() &&
GenericService.class != invoker.getInterface()) {
Throwable
throwable = result.getException();
if(throwable.getClass().equals(RuntimeException.class)) {
RuntimeException exception =
(RuntimeException) throwable;
return new
MyExceptionResult(exception);
}
}
return result;
}
private static class
MyExceptionResult implements Result{
private MyException e;
MyExceptionResult(RuntimeException
r) {
this.e =
new MyException(r.getMessage() + "-------Filter");
}
@Override
public Object getValue() {
return
null;
}
@Override
public Throwable getException() {
return
e;
}
@Override
public boolean hasException() {
return
true;
}
@Override
public Object recreate() throws Throwable
{
return
null;
}
@Override
public Object getResult() {
return
null;
}
@Override
public Map<String,
String> getAttachments() {
return
null;
}
@Override
public String getAttachment(String s) {
return
null;
}
@Override
public String getAttachment(String s, String s1)
{
return
null;
}
}
}
关键:Activate注解中的value指向下文com.alibaba.dubbo.rpc.Filter中的exceptionfilter
2.创建com.alibaba.dubbo.rpc.Filter
在resources下创建META-INF/dubbo/com.alibaba.dubbo.rpc.Filter,内容为:exceptionfilter=com.scn7th.filter.MyExceptionFilter
3.在appication.properties中增加dubbo.provider.filter=exceptionfilter
dubbo.application.name=provider
dubbo.application.logger=slf4j
dubbo.annotation.package=com.scn7th.provider
dubbo.protocol.name=dubbo
dubbo.protocol.port=20881
dubbo.protocol.accessLog=true
dubbo.provider.timeout=3000
dubbo.provider.retries=1
dubbo.provider.delay=-1
dubbo.provider.filter=exceptionfilter
dubbo.registr.protocol=zookeeper
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.register=true
dubbo.registry.subscribe=true
dubbo.
spring.redis.host=
4.抛给consumer的MyException
public class MyException extends Exception{
public
MyException(String message) {
super(message);
}
}
5.dubbo接口及其实现类
public interface IDubboDemoService {
String sayHello(String
name) throws MyException;
String sayYourAge(int
age) throws MyException;
}
@Component
@Service(version="1.0.0")
public class DubboDemoServiceImpl implements IDubboDemoService
{
@Override
public String
sayHello(String name)
throws MyException {
if(name.equals("Tom")) {
throw new
RuntimeException("The Name is Tom! He is not a good man!");
}
return "hello " + name;
}
@Override
public String
sayYourAge(int age)
throws MyException{
return null;
}
}
三、dubbo-consumer项目
1.dubbo服务调用
@Service
public class MyService {
@Reference(version =
"1.0.0")
private
IDubboDemoService dubboDemoService;
public String
hello(String name) throws MyException {
String result =
dubboDemoService.sayHello(name);
return result;
}
}
2.controller接收异常
@RestController
@RequestMapping("/")
public class MyController {
@Autowired
private MyService
myService;
@RequestMapping("/user/name/{name}")
public String
test(@PathVariable String name) {
try {
String
result = myService.hello(name);
return
result;
}catch (MyException e)
{
return
e.getMessage();
}
}
}
测试:
在浏览器中输入http://localhost:8088/user/name/Tom
加载中,请稍候......