Dubbo之Filter原理

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Dubbo之Filter原理
⼀、使⽤⽰例
(1)创建⼀个XxxFilter,并实现com.alibaba.dubbo.rpc.Filter 这个类
public class MyDubboFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// before filter ...
Result result = invoker.invoke(invocation);
// after filter ...
return result;
}
}
(2)添加META-INF/dubbo/com.alibaba.dubbo.rpc.Filter ⽂件,并添加如下内容
myFilter=com.test.MyDubboFilter
(3)配置xml
<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService" filter="myFilter"> <dubbo:method name="sayHello" retries="0"></dubbo:method>
</dubbo:reference>
配置⽅式
xml配置⽅式
<!-- 消费⽅调⽤过程拦截 -->
<dubbo:reference filter="xxx"/>
<!-- 消费⽅调⽤过程缺省拦截器,将拦截所有reference -->
<dubbo:consumer filter="xxx"/>
<!-- 提供⽅调⽤过程拦截 -->
<dubbo:service filter="xxx"/>
<!-- 提供⽅调⽤过程缺省拦截器,将拦截所有service -->
<dubbo:provider filter="xxx"/>
注解配置⽅式
@Activate(group = Constants.CONSUMER, order = -10000)
public class MyDubboFilter implements Filter {
}
⼆、源码分析
通过调试我们来看⼀下它的实现机制
(1)Filter的加载顺序问题
通过@Activate注解中的order属性,Activate表⽰激活
@Activate(group = Constants.CONSUMER, order = -10000)
public class ConsumerContextFilter implements Filter {
}
@Activate(group = Constants.CONSUMER)
public class FutureFilter implements Filter {
}
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) // 指定消费者和⽣产者
public class MonitorFilter implements Filter {
}
将MyDubboFilter改成 -1000000,发现执⾏顺序在ConsumerContextFilter之前了,如下图所⽰
(2)原⽣的Filter
Dubbo原⽣的Filter很多,RpcContext,accesslog等功能都可以通过Dubbo来实现,下⾯我们来介绍⼀下Consumer端⽤于上下⽂传递的ConsumerContextFilter
@Activate(group = Constants.CONSUMER, order = -10000)
public class ConsumerContextFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
RpcContext.getContext()
.setInvoker(invoker)
.setInvocation(invocation)
.setLocalAddress(NetUtils.getLocalHost(), 0)
.setRemoteAddress(invoker.getUrl().getHost(),
invoker.getUrl().getPort());
if (invocation instanceof RpcInvocation) {
((RpcInvocation) invocation).setInvoker(invoker);
}
try {
return invoker.invoke(invocation);
} finally {
RpcContext.getContext().clearAttachments();
}
}
}
此Filter记录了调⽤过程中的状态信息,并且通过invocation对象将客户端设置的attachments参数传递到服务端。

并且在调⽤完成后清除这些参数,这就是为什么请求状态信息可以按次记录并且进⾏传递。

Dubbo中已经实现的Filter⼤概有⼆⼗⼏个,它们的⼊⼝都是ProtocolFilterWrapper,ProtocolFilterWrapper对Protocol做了Wrapper,会在加载扩展的时候被加载进来,下⾯我们来看下这个Filter链是如何构造的。

加载机制
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
// 获取已经激活的Filter(调⽤链,这⾥的调⽤链是已经排好序的)
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
// 遍历
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
// 典型的装饰器模式,将invoker⽤filter逐层进⾏包装
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
// 重点,每个filter在执⾏invoke⽅法时,会触发其下级节点的invoke⽅法,最后⼀级节点即为最原始的服务
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
// 服务端暴露服务
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
// 客户端引⽤服务
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
return protocol.refer(type, url);
}
return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
}
通过上述代码我们可以看到,在buildInvokerChain中,先获取所有已经激活的调⽤链,这⾥的调⽤链是已经排好序的。

再通过Invoker来构造出⼀个Filter的调⽤链,最后构建出的调⽤链⼤致可以表⽰为:Filter1->Filter2->Filter3->......->Invoker,下⾯我们来看⼀下,第⼀步中获取已经激活的调⽤链的详细流程
调⽤链流程
public List<T> getActivateExtension(URL url, String key, String group) {
String value = url.getParameter(key);
return getActivateExtension(url, value == null || value.length() == 0 ? null : MA_SPLIT_PATTERN.split(value), group);
}
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<T>();
List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
// 如果⽤户配置的filter列表名称中不包含-default,则加载标注了Activate注解的filter列表
if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
// 加载配置⽂件,获取所有标注有Activate注解的类,存⼊cachedActivates中
getExtensionClasses();
for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Activate activate = entry.getValue();
// Activate注解可以指定group,这⾥是看注解指定的group与我们要求的group是否匹配
if (isMatchGroup(group, activate.group())) {
T ext = getExtension(name);
// 对于每⼀个dubbo中原⽣的filter,需要满⾜以下3个条件才会被加载:
// 1.⽤户配置的filter列表中不包含该名称的filter
// 2.⽤户配置的filter列表中不包含该名称前加了"-"的filter
// 3.该Activate注解被激活,具体激活条件随后详解
if (! names.contains(name) && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)
&& isActive(activate, url)) {
exts.add(ext);
}
}
}
// 排序
Collections.sort(exts, PARATOR);
}
// 加载⽤户在spring配置⽂件中配置的filter列表
List<T> usrs = new ArrayList<T>();
for (int i = 0; i < names.size(); i ++) {
String name = names.get(i);
if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX)
&& ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
if (Constants.DEFAULT_KEY.equals(name)) {
if (usrs.size() > 0) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
T ext = getExtension(name);
usrs.add(ext);
}
}
}
if (usrs.size() > 0) {
exts.addAll(usrs);
}
return exts;
}
通过以上代码可以看到,⽤户⾃⼰配置的Filter中,有些是默认激活,有些是需要通过配置⽂件来激活。

⽽所有Filter的加载顺序,也是先处理Dubbo的默认Filter,再来处理⽤户⾃⼰定义并且配置的Filter。

通过"-"配置,可以替换掉Dubbo的原⽣Filter,通过这样的设计,可以灵活地替换或者修改Filter的加载顺序。

总结:
filter被分为两类,⼀类是标注了Activate注解的filter,包括dubbo原⽣的和⽤户⾃定义的;⼀类是⽤户在spring配置⽂件中⼿动注⼊的filter 对标注了Activate注解的filter,可以通过before、after和order属性来控制它们之间的相对顺序,还可以通过group来区分服务端和消费端
⼿动注⼊filter时,可以⽤default来代表所有标注了Activate注解的filter,以此来控制两类filter之间的顺序
⼿动注⼊filter时,可以在filter名称前加⼀个"-"表⽰排除某⼀个filter,⽐如说如果配置了⼀个-default的filter,将不再加载所有标注了Activate 注解的filter。

相关文档
最新文档