Dubbo过滤器原理解析

一. 自定义过滤器配置:

dubbo filter可能是我们使用dubbo时最经常自定义的。通常用作一些公共处理,比如公共的日志打印让代码更简洁,和如上示例的通用异常结果处理等,配置过程如下:

1. 定义过滤器实现org.apache.dubbo.rpc.Filter接口,并在类上增加@Activate注解激活。

注解常用参数:

group:URL(org.apache.dubbo.common.URL)中的分组如果匹配则激活,如provider、consumer

value:URL中如果包含该key值则激活

before:填写扩展点列表,表示哪些扩展点要在本扩展点之前激活

after:表示哪些扩展点要在本扩展点之前激活

order:优先级(执行顺序)

过滤器类示例:

@Activate(
        group = {CommonConstants.PROVIDER},
        order = 1
)
public class DubboExceptionFilter implements Filter, Filter.Listener {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
    }

    @Override
    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
    }

}

2. 在配置文件 META-INF/dubbo/org.apache.dubbo.rpc.Filter 中增加:

xxFilter = 自定义Filter

例:

dubboExceptionFilter=com.wenzq.filter.DubboExceptionFilter

使用dubbo提供的SPI扩展机制,扩展很便捷。

3. 如果需要排除指定过滤器,使其不生效,可在xml中配置filter名称前加"-"

例:

<dubbo:provider filter="-dubboLogFilter" ... ... />
<dubbo:consumer filter="-dubboLogFilter" ... ... />
<dubbo:service id="xxxProvider" interface="com.xxx.xxx" filter="-dubboLogFilter" ... ... />
<dubbo:reference id="xxxConsumer" interface="com.xxx.xxx" filter="-dubboLogFilter" ... ... />

二. Dubbo过滤器原理:

使用起来这么便捷,那么过滤器是如何加载配置和执行的呢,接下来根据提供者、消费者过滤器一一分析。

Provider:

dubbo暴露服务时序大致如下:

从上图可看出服务暴露调用顺序:

ServiceConfig.export -> RegistryProtocol.export -> DubboProtocol.export

此处我们重点关注DubboProtocol,注意DubboProtocol为包装后的增强实现(dubbo的SPI扩展点自适应机制,此处简单类比成spring的AOP,详细了解SPI机制可参考 官方文档),调用DubboProtocol时实际调用为:

ProtocolListenerWrapper -> ProtocolFilterWrapper -> QosProtocolWrapper -> DubboProtocol

构建过滤器链就在ProtocolListenerWrapper.export方法中完成,相关源码如下:

@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_KEY, CommonConstants.PROVIDER));
}

/**
* 构建过滤器链
*/
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    // 基于dubbo SPI active机制加载filter列表
    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);
            // 新建过滤器节点,并放入当前节点
            last = new FilterNode<T>(invoker, last, filter);
        }
    }

    return last;
}

其中入参invoker为实际调用,通过ExtensionLoader获取过滤器列表(已根据order排序),并以invoker作为最后一个节点倒序构建过滤器链。

接下来看过滤器链节点执行过程:每个节点执行invoke方法时,内部实际调用节点持有filter的invoke方法,执行时传入下一个节点。当前filter逻辑执行完毕后,内部会手动调用下一个节点的invoke方法,依次向下调用直到最终invoker,最终invoker执行完毕返回结果至顶层节点,调用完成,所以过滤器链最终调用顺序为:Filter1 -> Filter2 -> Filter3 ... ... -> Invoker。

可以看出调用链的每个节点都为invoker增加了功能,属装饰器模式的一种实现。

class FilterNode<T> implements Invoker<T>{

    @Override
    public Result invoke(Invocation invocation) throws RpcException {
        Result asyncResult;
        try {
            // 执行invoke传入下一个节点
            asyncResult = filter.invoke(next, invocation);
        } catch (Exception e) {
            if (filter instanceof ListenableFilter) {
                ListenableFilter listenableFilter = ((ListenableFilter) filter);
                try {
                    Filter.Listener listener = listenableFilter.listener(invocation);
                    if (listener != null) {
                        listener.onError(e, invoker, invocation);
                    }
                } finally {
                    listenableFilter.removeListener(invocation);
                }
            } else if (filter instanceof Filter.Listener) {
                Filter.Listener listener = (Filter.Listener) filter;
                listener.onError(e, invoker, invocation);
            }
            throw e;
        } finally {

        }
        return asyncResult.whenCompleteWithContext((r, t) -> {
            if (filter instanceof ListenableFilter) {
                ListenableFilter listenableFilter = ((ListenableFilter) filter);
                Filter.Listener listener = listenableFilter.listener(invocation);
                try {
                    if (listener != null) {
                        if (t == null) {
                            listener.onResponse(r, invoker, invocation);
                        } else {
                            listener.onError(t, invoker, invocation);
                        }
                    }
                } finally {
                    listenableFilter.removeListener(invocation);
                }
            } else if (filter instanceof Filter.Listener) {
                Filter.Listener listener = (Filter.Listener) filter;
                if (t == null) {
                    listener.onResponse(r, invoker, invocation);
                } else {
                    listener.onError(t, invoker, invocation);
                }
            }
        });
    }

     /**
     * 省略部分代码 ... ...
     */    

}

Consumer:

dubbo服务引用时序大致如下:

可以看出调用顺序:

RefrenceConfig.refer -> RegistryProtocol.refer -> DubboProtocol.refer

DubboProtocol与提供者同理,构建过滤器链在ProtocolListenerWrapper.refer方法中完成。

buildInvokerChain方法与服务提供者相同,过滤器调用也是类似的。

@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_KEY, CommonConstants.CONSUMER);
}

三. 原生过滤器:

dubbo原生提供多个过滤器,配置在META-INF/dubbo/internal/org.apache.dubbo.rpc.filter文件中(详情见表格,绿色代表提供者/消费者生效,值为order)。接下来简要讲解过滤器用途和主要源码,篇幅原因挑选部分过滤器讲解。

说明:本文源码基于dubbo 2.7.16-release

dubbo原生过滤器

提供者:

过滤器调用顺序:EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter -> ExceptionFilter

EchoFilter

用于回音测试,所谓回音测试就是Provider返回Consumer请求数据。

@Activate(group = CommonConstants.PROVIDER, order = -110000)
public class EchoFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
        // 判断方法名是否$echo && 参数长度是否等于1
        if (inv.getMethodName().equals($ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) {
            // 将传入参数返回(回声)
            return AsyncRpcResult.newDefaultAsyncResult(inv.getArguments()[0], inv);
        }
        return invoker.invoke(inv);
    }

}

ClassLoaderFilter

类加载过滤器,诈一看代码有点懵,切换线程的类加载器干啥?因为当前线程类加载器可能与Invoker接口类加载器不一致,但是当前线程中需要获取 Invoker 的类加载器中的一些 Class,以防出现 ClassNotFoundException异常。

@Activate(group = CommonConstants.PROVIDER, order = -30000)
public class ClassLoaderFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 获取当前线程原类加载器
        ClassLoader ocl = Thread.currentThread().getContextClassLoader();
        // 切换当前线程的类加载器为服务接口的类加载器
        Thread.currentThread().setContextClassLoader(invoker.getInterface().getClassLoader());
        try {
            // 执行invoker
            return invoker.invoke(invocation);
        } finally {
            // 完成后,切换当前线程的类加载器为原类加载器
            Thread.currentThread().setContextClassLoader(ocl);
        }
    }

}

ContextFilter

服务提供者上下文过滤器,对应消费者上下文过滤器为ConsumerContextFilter。讲解ContextFilter就不得不谈谈RpcContext,dubbo提供了这个上下文用于给提供者/消费者隐式传递参数,并且只在当前调用链上生效。用途如:分布式链路追踪,traceId、spanId传递等。

消费端设置参数:

RpcContext.getContext().getObjectAttachments().put("consumerInfo","params");

服务端读取参数:

Object providerInfo = RpcContext.getServerContext().getObjectAttachments().get("consumerInfo");

反之服务端设置参数、消费端获取参数亦可。

@Activate(group = PROVIDER, order = Integer.MIN_VALUE)
public class ContextFilter implements Filter, Filter.Listener {

    private static final String TAG_KEY = "dubbo.tag";

    private static final Set<String> UNLOADING_KEYS;

    static {
        UNLOADING_KEYS = new HashSet<>(128);
        UNLOADING_KEYS.add(PATH_KEY);
        UNLOADING_KEYS.add(INTERFACE_KEY);
        UNLOADING_KEYS.add(GROUP_KEY);
        UNLOADING_KEYS.add(VERSION_KEY);
        UNLOADING_KEYS.add(DUBBO_VERSION_KEY);
        UNLOADING_KEYS.add(TOKEN_KEY);
        UNLOADING_KEYS.add(TIMEOUT_KEY);
        UNLOADING_KEYS.add(TIMEOUT_ATTACHMENT_KEY);

        // Remove async property to avoid being passed to the following invoke chain.
        UNLOADING_KEYS.add(ASYNC_KEY);
        UNLOADING_KEYS.add(TAG_KEY);
        UNLOADING_KEYS.add(FORCE_USE_TAG);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Map<String, Object> attachments = invocation.getObjectAttachments();
        // 新建attachments
        if (attachments != null) {
            Map<String, Object> newAttach = new HashMap<>(attachments.size());
            for (Map.Entry<String, Object> entry : attachments.entrySet()) {
                String key = entry.getKey();
                if (!UNLOADING_KEYS.contains(key)) {
                    newAttach.put(key, entry.getValue());
                }
            }
            attachments = newAttach;
        }

        // 获取并设置RpcContext
        RpcContext context = RpcContext.getContext();
        context.setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
        String remoteApplication = (String) invocation.getAttachment(REMOTE_APPLICATION_KEY);
        if (StringUtils.isNotEmpty(remoteApplication)) {
            context.setRemoteApplicationName(remoteApplication);
        } else {
            context.setRemoteApplicationName((String) context.getAttachment(REMOTE_APPLICATION_KEY));
        }

        long timeout = RpcUtils.getTimeout(invocation, -1);
        if (timeout != -1) {
            context.set(TIME_COUNTDOWN_KEY, TimeoutCountDown.newCountDown(timeout, TimeUnit.MILLISECONDS));
        }

        // 设置RpcContext设置/添加attachments
        if (attachments != null) {
            if (context.getObjectAttachments() != null) {
                context.getObjectAttachments().putAll(attachments);
            } else {
                context.setObjectAttachments(attachments);
            }
        }
        // 设置RpcInvocation的invoker
        if (invocation instanceof RpcInvocation) {
            ((RpcInvocation) invocation).setInvoker(invoker);
        }

        try {
            // 设置执行后不清除上下文
            context.clearAfterEachInvoke(false);
            return invoker.invoke(invocation);
        } finally {
            // 设置执行后清除上下文
            context.clearAfterEachInvoke(true);
            // 并发场景下必须从当前线程移除RPCContext,所以同一线程每次调用都重新创建上下文
            RpcContext.removeContext(true);
            RpcContext.removeServerContext();
        }
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        // 传递attachments到结果
        appResponse.addObjectAttachments(RpcContext.getServerContext().getObjectAttachments());
    }

    @Override
    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {

    }
}

TimeOutFilter

超时过滤器

@Activate(group = CommonConstants.PROVIDER)
public class TimeoutFilter implements Filter, Filter.Listener {

    private static final Logger logger = LoggerFactory.getLogger(TimeoutFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        // 从上下文中获取超时计时器
        Object obj = RpcContext.getContext().get(TIME_COUNTDOWN_KEY);
        if (obj != null) {
            TimeoutCountDown countDown = (TimeoutCountDown) obj;
            // 判断是否超时过期
            if (countDown.isExpired()) {
                // 超时情况,清空response
                ((AppResponse) appResponse).clear();
                if (logger.isWarnEnabled()) {
                    // 输出警告日志
                    logger.warn("invoke timed out. method: " + invocation.getMethodName() + " arguments: " +
                            Arrays.toString(invocation.getArguments()) + " , url is " + invoker.getUrl() +
                            ", invoke elapsed " + countDown.elapsedMillis() + " ms.");
                }
            }
        }
    }

    @Override
    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {

    }
}

MonitorFilter

监控过滤器,用于采集请求成功数、失败数、吞吐量、当前并发数、接口响应时长等。配置monitor后,MonitorFilter将采集监控信息并完成上报。

配置示例:

 <dubbo:monitor address="dubbo://127.0.0.1:10880" />
@Activate(group = {PROVIDER, CONSUMER})
public class MonitorFilter implements Filter, Filter.Listener {

    private static final Logger logger = LoggerFactory.getLogger(MonitorFilter.class);
    private static final String MONITOR_FILTER_START_TIME = "monitor_filter_start_time";
    private static final String MONITOR_REMOTE_HOST_STORE = "monitor_remote_host_store";

    /**
     * The Concurrent counter
     */
    private final ConcurrentMap<String, AtomicInteger> concurrents = new ConcurrentHashMap<String, AtomicInteger>();

    /**
     * The MonitorFactory
     */
    private MonitorFactory monitorFactory;

    public void setMonitorFactory(MonitorFactory monitorFactory) {
        this.monitorFactory = monitorFactory;
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
            invocation.put(MONITOR_FILTER_START_TIME, System.currentTimeMillis());
            invocation.put(MONITOR_REMOTE_HOST_STORE, RpcContext.getContext().getRemoteHost());
            // 获取计数器+1
            getConcurrent(invoker, invocation).incrementAndGet(); // count up
        }
        // 执行invoker
        return invoker.invoke(invocation);
    }

    private AtomicInteger getConcurrent(Invoker<?> invoker, Invocation invocation) {
        String key = invoker.getInterface().getName() + "." + invocation.getMethodName();
        return concurrents.computeIfAbsent(key, k -> new AtomicInteger());
    }

    @Override
    public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
        if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
            collect(invoker, invocation, result, (String) invocation.get(MONITOR_REMOTE_HOST_STORE), (long) invocation.get(MONITOR_FILTER_START_TIME), false);
            // 获取计数器-1
            getConcurrent(invoker, invocation).decrementAndGet(); // count down
        }
    }

    @Override
    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
        if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
            collect(invoker, invocation, null, (String) invocation.get(MONITOR_REMOTE_HOST_STORE), (long) invocation.get(MONITOR_FILTER_START_TIME), true);
            // 获取计数器-1
            getConcurrent(invoker, invocation).decrementAndGet(); // count down
        }
    }
    
    private void collect(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {
        try {
            URL monitorUrl = invoker.getUrl().getUrlParameter(MONITOR_KEY);
            // 通过监控工厂获取监控对象
            Monitor monitor = monitorFactory.getMonitor(monitorUrl);
            if (monitor == null) {
                return;
            }
            URL statisticsURL = createStatisticsUrl(invoker, invocation, result, remoteHost, start, error);
            monitor.collect(statisticsURL);
        } catch (Throwable t) {
            logger.warn("Failed to monitor count service " + invoker.getUrl() + ", cause: " + t.getMessage(), t);
        }
    }

    private URL createStatisticsUrl(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {
        // ---- service statistics ----
        // 计算调用耗时
        long elapsed = System.currentTimeMillis() - start;
        // 当前并发数量
        int concurrent = getConcurrent(invoker, invocation).get();
        String application = invoker.getUrl().getParameter(APPLICATION_KEY);
        // 接口名称
        String service = invoker.getInterface().getName();
        // 方法名称
        String method = RpcUtils.getMethodName(invocation);
        // 分组信息
        String group = invoker.getUrl().getParameter(GROUP_KEY);
        // 版本信息
        String version = invoker.getUrl().getParameter(VERSION_KEY);

        int localPort;
        String remoteKey, remoteValue;
        if (CONSUMER_SIDE.equals(invoker.getUrl().getParameter(SIDE_KEY))) {
            // 消费者时
            localPort = 0;
            remoteKey = MonitorService.PROVIDER;
            remoteValue = invoker.getUrl().getAddress();
        } else {
            // 提供者时
            localPort = invoker.getUrl().getPort();
            remoteKey = MonitorService.CONSUMER;
            remoteValue = remoteHost;
        }
        String input = "", output = "";
        if (invocation.getAttachment(INPUT_KEY) != null) {
            input = invocation.getAttachment(INPUT_KEY);
        }
        if (result != null && result.getAttachment(OUTPUT_KEY) != null) {
            output = result.getAttachment(OUTPUT_KEY);
        }
        // 返回统计URL
        return new URL(COUNT_PROTOCOL, NetUtils.getLocalHost(), localPort, service + PATH_SEPARATOR + method, MonitorService.APPLICATION, application, MonitorService.INTERFACE, service, MonitorService.METHOD, method, remoteKey, remoteValue, error ? MonitorService.FAILURE : MonitorService.SUCCESS, "1", MonitorService.ELAPSED, String.valueOf(elapsed), MonitorService.CONCURRENT, String.valueOf(concurrent), INPUT_KEY, input, OUTPUT_KEY, output, GROUP_KEY, group, VERSION_KEY, version);
    }


}

ExceptionFilter

异常处理过滤器

@Activate(group = CommonConstants.PROVIDER)
public class ExceptionFilter implements Filter, Filter.Listener {
    private Logger logger = LoggerFactory.getLogger(ExceptionFilter.class);
    
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }
    
    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        // 判断是否包含异常
        if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
            try {
                Throwable exception = appResponse.getException();
                
                // 1. 非运行时异常且是检查型异常时,直接抛出
                if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
                    return;
                }
                // 2. 判断接口声明中是否抛出目标异常,是则直接抛出
                try {
                    Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
                    Class<?>[] exceptionClasses = method.getExceptionTypes();
                    for (Class<?> exceptionClass : exceptionClasses) {
                        if (exception.getClass().equals(exceptionClass)) {
                            return;
                        }
                    }
                } catch (NoSuchMethodException e) {
                    return;
                }
                
                // 接口声明中没有包含目标异常,打印ERROR日志
                logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);
                
                // 3. 如果异常类和接口类型在同一jar中,直接抛出
                String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
                String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
                if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {
                    return;
                }
                // 4. 根据异常类包名前缀判断是否jdk异常,是则抛出
                String className = exception.getClass().getName();
                if (className.startsWith("java.") || className.startsWith("javax.")) {
                    return;
                }
                // 5. 判断是否dubbo异常,是则抛出
                if (exception instanceof RpcException) {
                    return;
                }
                
                // 6. 包装成RuntimeException抛出(填充异常内容)
                appResponse.setException(new RuntimeException(StringUtils.toString(exception)));
            } catch (Throwable e) {
                logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
            }
        }
    }
    
    @Override
    public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
        logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
    }
    
    public void setLogger(Logger logger) {
        this.logger = logger;
    }
}

消费者:

消费者过滤器调用顺序:ConsumerContextFilter->FutureFilter->MonitorFilter->GenericImplFilter(仅限泛化调用)

ConsumerContextFilter

服务消费者上下文过滤器

@Activate(group = CONSUMER, order = -10000)
public class ConsumerContextFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 获取并设置context
        RpcContext context = RpcContext.getContext();
        context.setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(NetUtils.getLocalHost(), 0)
                .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort())
                .setRemoteApplicationName(invoker.getUrl().getParameter(REMOTE_APPLICATION_KEY))
                .setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getParameter(APPLICATION_KEY));
        // 设置RpcInvocation的invoker
        if (invocation instanceof RpcInvocation) {
            ((RpcInvocation) invocation).setInvoker(invoker);
        }

        // 获取超时计时器(此处为用户最终配置超时时间)
        Object countDown = context.get(TIME_COUNTDOWN_KEY);
        if (countDown != null) {
            TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown;
            // 如果超时返回超时异常结果
            if (timeoutCountDown.isExpired()) {
                return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE,
                        "No time left for making the following call: " + invocation.getServiceName() + "."
                                + invocation.getMethodName() + ", terminate directly."), invocation);
            }
        }
        // 调用invoker并返回
        return invoker.invoke(invocation);
    }

}

MonitorFilter

同提供者

FutureFilter

FutureFilter调用之前、调用之后、出现异常时,会触发 oninvoke、onreturn、onthrow 三个事件,可以配置当事件发生时,通知对应类的对应方法。

详细可参考:官方示例

@Activate(group = CommonConstants.CONSUMER)
public class FutureFilter implements Filter, Filter.Listener {

    protected static final Logger logger = LoggerFactory.getLogger(FutureFilter.class);

    @Override
    public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
        fireInvokeCallback(invoker, invocation);
        return invoker.invoke(invocation);
    }

    @Override
    public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
        if (result.hasException()) {
            fireThrowCallback(invoker, invocation, result.getException());
        } else {
            fireReturnCallback(invoker, invocation, result.getValue());
        }
    }

    @Override
    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
        fireThrowCallback(invoker, invocation, t);
    }

    private void fireInvokeCallback(final Invoker<?> invoker, final Invocation invocation) {
        // 获取异步方法MethodInfo
        final AsyncMethodInfo asyncMethodInfo = getAsyncMethodInfo(invoker, invocation);
        if (asyncMethodInfo == null) {
            return;
        }
        // 获取回调方法、回调实例
        final Method onInvokeMethod = asyncMethodInfo.getOninvokeMethod();
        final Object onInvokeInst = asyncMethodInfo.getOninvokeInstance();

        if (onInvokeMethod == null && onInvokeInst == null) {
            return;
        }
        if (onInvokeMethod == null || onInvokeInst == null) {
            throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a oninvoke callback config , but no such " + (onInvokeMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
        }
        // 修改方法访问权限
        ReflectUtils.makeAccessible(onInvokeMethod);
        // 获取调用入参
        Object[] params = invocation.getArguments();
        try {
            // 调用回调方法(反射)
            onInvokeMethod.invoke(onInvokeInst, params);
        } catch (InvocationTargetException e) {
            // 捕获异常调用异常处理方法fireThrowCallback
            fireThrowCallback(invoker, invocation, e.getTargetException());
        } catch (Throwable e) {
            fireThrowCallback(invoker, invocation, e);
        }
    }

    private void fireReturnCallback(final Invoker<?> invoker, final Invocation invocation, final Object result) {
        // 获取异步方法MethodInfo
        final AsyncMethodInfo asyncMethodInfo = getAsyncMethodInfo(invoker, invocation);
        if (asyncMethodInfo == null) {
            return;
        }
        // 获取回调方法、回调实例
        final Method onReturnMethod = asyncMethodInfo.getOnreturnMethod();
        final Object onReturnInst = asyncMethodInfo.getOnreturnInstance();

        if (onReturnMethod == null && onReturnInst == null) {
            return;
        }

        if (onReturnMethod == null || onReturnInst == null) {
            throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onReturnMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
        }
        // 修改方法访问权限
        ReflectUtils.makeAccessible(onReturnMethod);
        // 获取调用入参
        Object[] args = invocation.getArguments();
        Object[] params;
        Class<?>[] rParaTypes = onReturnMethod.getParameterTypes();
        // 判断回调方法入参是否大于1
        if (rParaTypes.length > 1) {
            // 如果参数数量为2且第二个参数为Object数组,则1设置调用结果,2设置调用入参
            if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
                params = new Object[2];
                params[0] = result;
                params[1] = args;
            } else {
                // 否则1设置调用结果,后续顺序设置入参
                params = new Object[args.length + 1];
                params[0] = result;
                System.arraycopy(args, 0, params, 1, args.length);
            }
        } else {
            // 参数数量为1,直接赋值调用结果
            params = new Object[]{result};
        }
        try {
            // 调用回调方法(反射)
            onReturnMethod.invoke(onReturnInst, params);
        } catch (InvocationTargetException e) {
            // 捕获异常调用异常处理方法fireThrowCallback
            fireThrowCallback(invoker, invocation, e.getTargetException());
        } catch (Throwable e) {
            fireThrowCallback(invoker, invocation, e);
        }
    }

    // 核心代码与fireReturnCallback一致,不赘述
    private void fireThrowCallback(final Invoker<?> invoker, final Invocation invocation, final Throwable exception) {
        final AsyncMethodInfo asyncMethodInfo = getAsyncMethodInfo(invoker, invocation);
        if (asyncMethodInfo == null) {
            return;
        }

        final Method onthrowMethod = asyncMethodInfo.getOnthrowMethod();
        final Object onthrowInst = asyncMethodInfo.getOnthrowInstance();

        if (onthrowMethod == null && onthrowInst == null) {
            return;
        }
        if (onthrowMethod == null || onthrowInst == null) {
            throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onthrow callback config , but no such " + (onthrowMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
        }
        ReflectUtils.makeAccessible(onthrowMethod);
        Class<?>[] rParaTypes = onthrowMethod.getParameterTypes();
        if (rParaTypes[0].isAssignableFrom(exception.getClass())) {
            try {
                Object[] args = invocation.getArguments();
                Object[] params;

                if (rParaTypes.length > 1) {
                    if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
                        params = new Object[2];
                        params[0] = exception;
                        params[1] = args;
                    } else {
                        params = new Object[args.length + 1];
                        params[0] = exception;
                        System.arraycopy(args, 0, params, 1, args.length);
                    }
                } else {
                    params = new Object[]{exception};
                }
                onthrowMethod.invoke(onthrowInst, params);
            } catch (Throwable e) {
                logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), e);
            }
        } else {
            logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), exception);
        }
    }

    private AsyncMethodInfo getAsyncMethodInfo(Invoker<?> invoker, Invocation invocation) {
        AsyncMethodInfo asyncMethodInfo = (AsyncMethodInfo) invocation.get(ASYNC_METHOD_INFO);
        if (asyncMethodInfo != null) {
            return asyncMethodInfo;
        }

        ConsumerModel consumerModel = ApplicationModel.getConsumerModel(invoker.getUrl().getServiceKey());
        if (consumerModel == null) {
            return null;
        }

        String methodName = invocation.getMethodName();
        if (methodName.equals($INVOKE)) {
            methodName = (String) invocation.getArguments()[0];
        }

        // 返回AsyncMethodInfo(初始化:ReferenceConfig.init -> AbstractConfig.convertMethodConfig2AsyncInfo)
        return consumerModel.getAsyncInfo(methodName);
    }

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dubbo服务过滤器可以用于在Dubbo服务调用的过程中对请求和响应进行预处理和后处理,例如权限控制、日志记录、统计信息等。在Dubbo中,可以通过配置<provider>或<consumer>标签下的<filter>元素来添加服务过滤器。具体的配置方法如下: 1. 创建一个服务过滤器类,实现org.apache.dubbo.common.extension.Activate接口,并重写filter方法。例如: ```java @Activate(group = "provider") public class MyFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { // 在这里添加过滤器的逻辑 return invoker.invoke(invocation); } } ``` 2. 在服务提供者或服务消费者的配置文件中,添加<filter>元素来引用服务过滤器。例如: ```xml <!-- 服务提供者配置 --> <dubbo:service interface="com.example.SomeService" ref="someService"> <dubbo:method name="someMethod" timeout="5000"> <dubbo:filter ref="myFilter" /> </dubbo:method> </dubbo:service> <!-- 服务消费者配置 --> <dubbo:reference id="someService" interface="com.example.SomeService"> <dubbo:method name="someMethod" timeout="5000"> <dubbo:filter ref="myFilter" /> </dubbo:method> </dubbo:reference> ``` 注意,<filter>元素必须放在<method>元素内部,以便对每个方法都应用过滤器。如果想要对所有方法都应用过滤器,则可以将<filter>元素放在<service>或<reference>元素内部。另外,如果服务过滤器需要传递参数,则可以通过<parameter>元素来配置。例如: ```xml <dubbo:filter ref="myFilter"> <dubbo:parameter key="param1" value="value1" /> <dubbo:parameter key="param2" value="value2" /> </dubbo:filter> ``` 在服务过滤器中可以通过调用invocation.getAttachment(key)方法来获取这些参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值