filter概述
- dubbo filter与servlet filter 或 XXX filter ... 设计思路一样;在目标方法执行前, 后插入filter功能代码,实现类似AOP的能力
- 多个filter在排好序后组成调用链执行;责任链设计模式
- dubbo filter 通常分为 :provider 和 consumer两种,通过 @Activate(group = CONSUMER) 注解中group参数可进行区分,服务调用方 只会加载执行“group = CONSUMER”的filter,服务提供方“group = Provider”的filter
dubbo filter源码分析
相关接口概念
-
Invocation,Invoker,Invoker 之间仅存在方法参数层面的依赖关系
-
Invocation 可理解为java方法的元数据对象
-
Invoker 可理解为java方法执行调用器(Invocation 作为方法参数)
-
Invoker 执行invoke方法可理解为目标方法被执行
-
Filter 中接口方法持有Invoker,Invocation,可理解为目标方法执行器与目标方法元数据
@SPI public interface Filter { /** * filter 接口方法 * invoker 方法调用对象 * invocation 方法名/参数/返回值... 数据结构 */ Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException; interface Listener { // 调用调用 void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation); // 异常调用 void onError(Throwable t, Invoker<?> invoker, Invocation invocation); } } // 方法调用对象 public interface Invoker<T> extends Node { Class<T> getInterface(); // 方法调用 Result invoke(Invocation invocation) throws RpcException; } // 方法对象 public interface Invocation { String getTargetServiceUniqueName(); String getMethodName(); String getServiceName(); ... }
filter的链式调用
ProtocolFilterWrapper#buildInvokerChain方法
-
ExtensionLoader加载出本次调用需要的filter列表,并已排好序
-
buildInvokerChain 方法参数中的invoker 可理解为最初的目标方法执行器
-
for循环为每个filter创建一个invoker并在invoker#invoke 方法中调用filter#invoke方法;filter0对应invoker0... filter2对应invoker2,srcInvoker为ProtocolFilterWrapper#buildInvokerChain中Invoker参数对象
-
具体的每个filter实现类会调用 invoker.invoke(invocation);
-
for循环倒序创建invoker,循环结束形成的invoker链的执行顺序与filter列表顺序一致
-
一次rpc调用 filter 与 invoker 对象有n 个与n+1个,但Invocation对象只有一个;【姑且解释为invoker 与 Invocation分开设计的一个原因】
-
初次接触filter,invoker链可能有点混乱,建议看下图或自己画图
-
调用关系如图:
public class ProtocolFilterWrapper implements Protocol { // invoker 为目标方法 private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) { // 目标方法 Invoker<T> last = invoker; // 加载active中的filter 已根据order排好序 List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); if (!filters.isEmpty()) { // for循环 倒序将filter包装成invoker对象 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 Result invoke(Invocation invocation) throws RpcException { Result asyncResult; try { // 执行filter调用方法 asyncResult = filter.invoke(next, invocation); } catch(Exception e) { if (filter instanceof Filter.Listener) { Filter.Listener listener = (Filter.Listener) filter; listener.onError(e, invoker, invocation); } } final() { } asyncResult.whenCompleteWithContext(r, t) -> { // 有实现Filter.Listener接口的filter实现类会执行此代码 if (t == null && filter instanceof Filter.Listener) { listener.onResponse(r, invoker, invocation); } if (t == null && filter instanceof Filter.Listener) { listener.onError(t, invoker, invocation); } } } } } } return last; } }
consumer, provider 分组
-
ProtocolFilterWrapper#export 服务提供方暴露方法时传入group="provider"参数
-
ProtocolFilterWrapper#refer 服务调用方引用方法时传入group="consumer"参数
-
export, refer 返回值是已包含filter链的invoker对象
public class ProtocolFilterWrapper implements Protocol { @Override public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { if (UrlUtils.isRegistry(invoker.getUrl())) { return protocol.export(invoker); } return protocol.export(buildInvokerChain(invoker, "service.filter","provider")); } @Override public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (UrlUtils.isRegistry(url)) { return protocol.refer(type, url); } return buildInvokerChain(protocol.refer(type, url), "reference.filter", "consumer"); } }
dubbo 提供的filter
-
dubbo提供了很多filter有 访问|超时|异常 等日志打印类型, attr|context 等 参数设置类型,限流|异常封装|鉴权 等通用处理类型filter
-
ActiveLimitFilter 调用方并发数量控制,采用wati, notify 方式控制调用并发数
@Activate(group = CONSUMER, value = ACTIVES_KEY) public class ActiveLimitFilter implements Filter, Filter.Listener { private static final String ACTIVELIMIT_FILTER_START_TIME = "activelimit_filter_start_time"; @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { URL url = invoker.getUrl(); String methodName = invocation.getMethodName(); int max = invoker.getUrl().getMethodParameter(methodName, ACTIVES_KEY, 0); final RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()); // 方法维度控制是否可调用【原子计数器判断,调用成功则并发数+1】 // beginCount 返回false则调用并发数已达到最大值 if (!RpcStatus.beginCount(url, methodName, max)) { long timeout = invoker.getUrl().getMethodParameter(invocation.getMethodName(), TIMEOUT_KEY, 0); long start = System.currentTimeMillis(); long remain = timeout; synchronized (rpcStatus) { // dubbo check 判断并发数是否可以自增 // 此处必须用while循环,因为每次执行结束会进行 notifyAll所有线程 while (!RpcStatus.beginCount(url, methodName, max)) { try { // 释放锁,并进入wait状态 && 最大等待时间可控 rpcStatus.wait(remain); } catch (InterruptedException e) { // ignore } long elapsed = System.currentTimeMillis() - start; remain = timeout - elapsed; if (remain <= 0) { throw new RpcException(RpcException.LIMIT_EXCEEDED_EXCEPTION,...); } } } } invocation.put(ACTIVELIMIT_FILTER_START_TIME, System.currentTimeMillis()); return invoker.invoke(invocation); } @Override public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { String methodName = invocation.getMethodName(); URL url = invoker.getUrl(); int max = invoker.getUrl().getMethodParameter(methodName, ACTIVES_KEY, 0); // notify 所有等待rpcStatus 锁线程 RpcStatus.endCount(url, methodName, getElapsed(invocation), true); notifyFinish(RpcStatus.getStatus(url, methodName), max); } @Override public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { String methodName = invocation.getMethodName(); URL url = invoker.getUrl(); int max = invoker.getUrl().getMethodParameter(methodName, ACTIVES_KEY, 0); if (t instanceof RpcException) { RpcException rpcException = (RpcException) t; if (rpcException.isLimitExceed()) { return; } } // 调用失败需要 调用并发数-1 RpcStatus.endCount(url, methodName, getElapsed(invocation), false); // notify 所有等待rpcStatus 锁线程 notifyFinish(RpcStatus.getStatus(url, methodName), max); } private void notifyFinish(final RpcStatus rpcStatus, int max) { if (max > 0) { synchronized (rpcStatus) { rpcStatus.notifyAll(); } } } } -
ExecuteLimitFilter 服务端并发数控制,当超过最大设置并发数时则直接失败
-
TpsLimitFilter 服务器TPS限流filter,控制任意时间窗口内总的请求数量
_文中代码基于dubbo v_2.7.8-SNAPSHOT 版本,且有改动(为方便展示)