dubbo是一个特别棒的soa框架,但是有时候我们会考虑对其进行扩展,实现一些自定义的功能。今天我们就来简单说说通过dubbo提供的com.alibaba.dubbo.rpc.Filter接口实现自定义的拦截器,扩展dubbo的功能。
dubbo Filter是责任链模式的一种实现方式,类似于servlet中的filter、mybatis中的plugin等都使用了责任链模式,只是各自实现的方式有些差异,但都能达到异曲同工之妙。
我们通常会用dubbo的Filter来实现一些比较有意思的功能,比如在服务消费方(consumer)实现一个本地缓存、在服务提供方(Provider)实现日志记录、耗时最终、异步上报等。
此处以服务提供方实现日志记录为例:
package cn.lovecto.promotion.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.fastjson.JSON;
/**
* 日志过滤器
*
*/
public class DubboLogFilter implements Filter {
protected static final Logger LOG = LoggerFactory.getLogger("dubbo");
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation)
throws RpcException {
Object args[] = invocation.getArguments();
String argsJson = JSON.toJSONString(args);
long start = System.currentTimeMillis();
try {
return invoker.invoke(invocation);
} catch (RpcException re) {
LOG.error(String.format("Duubo rpc error, args:[ {} ].", argsJson), re);
throw re;
} catch (Throwable e) {
LOG.error(String.format("Duubo rpc error, args:[ {} ].", argsJson), e);
throw new RpcException("Dubbo server uncaught exception!", e);
} finally {
long spend = (System.currentTimeMillis() - start);
int clientPort = RpcContext.getContext().getRemotePort();
//获取调用方IP地址
String clientIP = RpcContext.getContext().getRemoteHost();
//记录日志
LOG.info(
"DubboRPC info: API[ {} ], method[ {} ], args[ {} ], spendTime[ {} ms ], clientIp[ {} ], clientPort[ {} ].",
invoker.getInterface().getSimpleName(),
invocation.getMethodName(), argsJson, spend, clientIP,
clientPort);
}
}
}
代码写好了,由于我们的项目是基于springboot的,我们在src/main/resources创建META-INF/dubbo目录,在src/main/resources/META-INF/dubbo新建一个文件名“com.alibaba.dubbo.rpc.Filter”的文件,里面的内容如下:
dubboLogFilter=cn.lovecto.promotion.filter.DubboLogFilter
我的dubbo相关的配置是放到res目录中的,有两个文件,dubbo-interfaces.xml和dubbo.properties。springboot的相关配置类如下:
@Configuration
@PropertySource("file:res/dubbo.properties")
@ImportResource({ "file:res/dubbo-interfaces.xml" })
public class DubboConfig {
}
dubbo.properties文件如下:
dubbo.consumer.name=service_promotion
dubbo.zookeeper.address=zookeeper://172.17.0.2:2181
dubbo.timeout=20000
dubbo.group=test
dubbo.version=0.0.1
dubbo-interfaces.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:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="${dubbo.consumer.name}"></dubbo:application>
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="${dubbo.zookeeper.address}" check="false" protocol="zookeeper"></dubbo:registry>
<dubbo:provider port="-1" filter="dubboLogFilter" retries="0" />
<!-- 要暴露的服务接口 -->
<dubbo:service group="service_promotion" version="${dubbo.version}" interface="cn.lovecto.api.IPageQueryService" ref="pageQueryServiceImpl" />
</beans>
dubbo-interfaces.xml中filter=”dubboLogFilter”就是我们刚刚上文提到的拦截器。