Filter

Filter是Dubbo里面非常重要的模块,Dubbo里面日志记录、超时等功能都是在这一部分实现。

如上一节在介绍扩展点加载时所述,在生成Protocol的invoker时,实际上使用了装饰模式,第一个是filter,第二个是listener。

我们先来看filter,具体ProtocolFilterWrapper类:

/**
* ListenerProtocol
*/
public class ProtocolFilterWrapper implements Protocol { private final Protocol protocol; public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
} private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (!filters.isEmpty()) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() { public Class<T> getInterface() {
return invoker.getInterface();
} public URL getUrl() {
return invoker.getUrl();
} public boolean isAvailable() {
return invoker.isAvailable();
} 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 int getDefaultPort() {
return protocol.getDefaultPort();
} 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);
} public void destroy() {
protocol.destroy();
} }

这个类有3个特点,第一它有一个参数为Protocol protocol的构造函数;第二,它实现了Protocol接口;第三,它使用职责链模式,对export和refer函数进行了封装。

对于函数封装,有点类似于tomcat的filter机制;我们来看buildInvokerChain函数:它读取所有的filter类,利用这些类封装invoker。

List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);

我们看文件:META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Filter

cache=com.alibaba.dubbo.cache.filter.CacheFilter
validation=com.alibaba.dubbo.validation.filter.ValidationFilter
echo=com.alibaba.dubbo.rpc.filter.EchoFilter
generic=com.alibaba.dubbo.rpc.filter.GenericFilter
genericimpl=com.alibaba.dubbo.rpc.filter.GenericImplFilter
token=com.alibaba.dubbo.rpc.filter.TokenFilter
accesslog=com.alibaba.dubbo.rpc.filter.AccessLogFilter
activelimit=com.alibaba.dubbo.rpc.filter.ActiveLimitFilter
classloader=com.alibaba.dubbo.rpc.filter.ClassLoaderFilter
context=com.alibaba.dubbo.rpc.filter.ContextFilter
consumercontext=com.alibaba.dubbo.rpc.filter.ConsumerContextFilter
exception=com.alibaba.dubbo.rpc.filter.ExceptionFilter
executelimit=com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter
deprecated=com.alibaba.dubbo.rpc.filter.DeprecatedFilter
compatible=com.alibaba.dubbo.rpc.filter.CompatibleFilter
timeout=com.alibaba.dubbo.rpc.filter.TimeoutFilter
trace=com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter
future=com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter
monitor=com.alibaba.dubbo.monitor.support.MonitorFilter

这其中涉及到很多功能,包括权限验证、异常、超时等等,当然可以预计计算调用时间等等应该也是在这其中的某个类实现的。

这里我们可以看到export和refer过程都会被filter过滤,那么如果记录接口调用时间时,服务器端部分只是记录接口在服务器端的执行时间,而客户端部分会记录接口在服务器端的执行时间+网络传输时间。

Listener

看到对应的类为:ProtocolListenerWrapper

/**
* ListenerProtocol
*/
public class ProtocolListenerWrapper implements Protocol { private final Protocol protocol; public ProtocolListenerWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
} public int getDefaultPort() {
return protocol.getDefaultPort();
} public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return new ListenerExporterWrapper<T>(protocol.export(invoker),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
} 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 new ListenerInvokerWrapper<T>(protocol.refer(type, url),
Collections.unmodifiableList(
ExtensionLoader.getExtensionLoader(InvokerListener.class)
.getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
} public void destroy() {
protocol.destroy();
} }

我们可以看到export和refer分别对应了不同的Wrapper; 经过debug,发现ExporterListener并没有实现类,同时通过debug也会发现ListenerExporterWrapper在执行过程中确实listeners变量是空的; 而对于ListenerInvokerWrapper,我们发现在文件META-INF/dubbo/internal/com.alibaba.dubbo.rpc.InvokerListener中:

deprecated=com.alibaba.dubbo.rpc.listener.DeprecatedInvokerListener

而对于DeprecatedInvokerListener实际上只是实现了

/**
* DeprecatedProtocolFilter
*/
@Activate(Constants.DEPRECATED_KEY)
public class DeprecatedInvokerListener extends InvokerListenerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(DeprecatedInvokerListener.class); public void referred(Invoker<?> invoker) throws RpcException {
if (invoker.getUrl().getParameter(Constants.DEPRECATED_KEY, false)) {
LOGGER.error("The service " + invoker.getInterface().getName() + " is DEPRECATED! Declare from " + invoker.getUrl());
}
} }

Dubbo实践(八)扩展点装饰的更多相关文章

  1. Dubbo实践(五)扩展Spring Schema

    先回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml version="1.0" encoding="UTF-8"?> ...

  2. Dubbo中SPI扩展机制解析

    dubbo的SPI机制类似与Java的SPI,Java的SPI会一次性的实例化所有扩展点的实现,有点显得浪费资源. dubbo的扩展机制可以方便的获取某一个想要的扩展实现,每个实现都有自己的name, ...

  3. 20145203盖泽双 《网络对抗技术》实践八:Web基础

    20145203盖泽双 <网络对抗技术>实践八:Web基础 1.实践目标 (1)编写Web前端--含有表单的HTML代码. (2)编写Web前端--javascipt验证用户名.密码的代码 ...

  4. Dubbo实践(六)Spring加载Bean流程

    根据上一小节对于spring扩展schema的介绍,大概可以猜到dubbo中相关的内容是如何实现的. 再来回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml ve ...

  5. nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点

    nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点 优点 所有的 web开发的点都考虑到了 agent 很有特色 文件夹规划到位 扩展能力优秀 缺点 最大的问题在于: 使用 ...

  6. 这个Dubbo注册中心扩展,有点意思!

    今天想和大家聊聊Dubbo源码中实现的一个注册中心扩展.它很特殊,也帮我解决了一个困扰已久的问题,刚刚在生产中用了,效果很好,迫不及待想分享给大家. Dubbo的扩展性非常灵活,可以无侵入源码加载自定 ...

  7. 灵感乍现!造了个与众不同的Dubbo注册中心扩展轮子

    hello大家好呀,我是小楼. 作为一名基础组件开发,服务好每一位业务开发同学是我们的义务(KPI). 客服群里经常有业务开发同学丢来一段代码.一个报错,而我们,当然要微笑服务,耐心解答. 有的问题, ...

  8. Dubbo实践(十七)telnet

    telnet的介绍可以参看<java网络编程3>中有一段介绍telnet,我们可以理解为,telnet命令是通过socket协议与服务器端通信.Dubbo提供了telnet命令去查看服务功 ...

  9. Dubbo实践(九)ExtensionFactory

    ExtensionLoader.java中注意到injectExtension函数是为了设置所生成的对象的field:其方法为对于有set函数的field进行设置.此时用到了ExtensionFact ...

随机推荐

  1. cf1090 I.Minimal Product(贪心)

    题意 题目链接 给出长度为\(n\)的序列\(a\),序列中的元素取值为\([-2e9, 2e9]\) 找到两个位置\((i, j) (i <j, a[i] < a[j])\),最小化\( ...

  2. Nodejs + express + ejs 之服务器demo

    var http=require("http"); var express=require("express"); var fs = require(" ...

  3. 基于openlayers2军事标绘,开源

    1.其实各GIS公司.网络上 都会有提供 军事标绘的功能,如arcgis 的,超图的.mapgis的:但大多数是非开源.且收费的.2.在这里要感谢超图,超图开源了标绘扩展符号库,我这里使用的就是超图的 ...

  4. WeinView 与 MITSUBISHI FX 系列 PLC 通讯范例

    1. 范例操作概述 此范例将介绍如何快捷简易地建立WEINVIEW HMI与MITSUBISHI FX系列 PLC通讯. 注意事项:通讯参数设置,通讯线接法. 2. 规划说明 (1) 新建简单 PLC ...

  5. GetModuleFileName和获取应用程序当前目录

    原文:http://www.cnblogs.com/xuemaxiongfeng/articles/2465544.html API函数GetModuleFileName():获得应用程序目录相对路径 ...

  6. 浅谈搜索引擎SEO(HTML/CSS)

    SEO:搜索引擎优化(免费): SEM:搜索引擎营销(付费). 它们两者的区别是: 1.SEM高投入,SEO低投入: 2.SEM短.效益块,SEO长期投入.增长慢: 3.新广告法颁布之后SEM广告位减 ...

  7. PRINCE2的优势有哪些?

    PRINCE2之所以迅速发展的原因之一是许多企业认识到建立适合自己企业的项目管理标准是一项耗时耗财的工作. 他们至少要花费6-12个月.成千上万个工时来建立一套方法,而这只是最初的成本. 之后他们必须 ...

  8. 【转】fatal error C1189: #error : missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS

    转自:http://blog.csdn.net/friendan/article/details/46576699 fatal error C1189: #error :  missing -D__S ...

  9. 如何在 Azure 中的经典 Windows 虚拟机上设置终结点

    在 Azure 中使用经典部署模型创建的所有 Windows 虚拟机都可以通过专用网络通道与同一云服务或虚拟网络中的其他虚拟机自动通信. 但是,Internet 或其他虚拟网络中的计算机需要终结点将入 ...

  10. Ionic控件之——按钮(Button)

    Ionic提供丰富的按钮特性,足以满足大部分的按钮实现需求. 一.HTML实现一个简单按钮: <button class="button"> 我是按钮 </but ...