consumer filter

本文详细解析了Dubbo中ProtocolFilterWrapper的buildInvokerChain方法如何构建Filter链,并介绍了ConsumerContextFilter、MonitorFilter和FutureFilter的功能及工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ProtocolFilterWrapper中buildInvokerChain方法把Filter链在一起,调用执行的时候,逐个执行filter,最后执行filter中的invoker。

//ProtocolFilterWrapper
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.size() > 0) {
        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;
}

上面代码中,last的视图:

我们这样看:匿名内部类 new Invoker<T> { ... }中,

封装了final Filter filter,final Invoker<T> next,还有final Invoker<T> invoker,然后把filter链在一起。

consumer端一共有3个filter:ConsumerContextFilter, MonitorFilter, FutureFilter

1. ConsumerContextFilter 对RpcContext做设置和清理

@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();
        }
    }

}

2. MonitorFilter 统计接口方法调用信息

3. FutureFilter  处理异步调用

@Activate(group = Constants.CONSUMER)
public class FutureFilter implements Filter {}

在DubboInvoker.doInvoke方法中,
如果是异步,则在RpcContext设置Future,并返回空的RpcResult:

ResponseFuture future = currentClient.request(inv, timeout) ;
RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));
return new RpcResult();

如果是同步,则调用Future.get()方法而阻塞:

RpcContext.getContext().setFuture(null);
ResponseFuture future = currentClient.request(inv, timeout);
Result result = (Result)future.get();
return  result;

FutureAdapter实现了Future接口,内部封装了一个ResponseFuture对象。
ResponseFuture是一个接口,DefaultFuture是主要实现类。

FutureFilter.asyncCallback()为DefaultFuture设置回调函数:

//FutureFilter.asyncCallback
ResponseFuture future = ((FutureAdapter<?>)f).getFuture();
future.setCallback(new ResponseCallback() {
    public void done(Object rpcResult) {
        ...
    }
    public void caught(Throwable exception) {
        ...
    }
});

 

//DefaultFuture
public void setCallback(ResponseCallback callback) {
    if (isDone()) {
        invokeCallback(callback);
    } else {
        boolean isdone = false;
        lock.lock();
        try{
            if (!isDone()) {
                this.callback = callback;
            } else {
                isdone = true;
            }
        }finally {
            lock.unlock();
        }
        if (isdone){
            invokeCallback(callback);
        }
    }
}
private void invokeCallback(ResponseCallback c){
    ResponseCallback callbackCopy = c;
    if (callbackCopy == null){
        throw new NullPointerException("callback cannot be null.");
    }
    c = null;
    Response res = response;
    if (res == null) {
        throw new IllegalStateException("response cannot be null. url:"+channel.getUrl());
    }
    
    if (res.getStatus() == Response.OK) {
        try {
            callbackCopy.done(res.getResult());
        } catch (Exception e) {
            logger.error("callback invoke error .reasult:" + res.getResult() + ",url:" + channel.getUrl(), e);
        }
    } else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
        try {
            TimeoutException te = new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage());
            callbackCopy.caught(te);
        } catch (Exception e) {
            logger.error("callback invoke error ,url:" + channel.getUrl(), e);
        }
    } else {
        try {
            RuntimeException re = new RuntimeException(res.getErrorMessage());
            callbackCopy.caught(re);
        } catch (Exception e) {
            logger.error("callback invoke error ,url:" + channel.getUrl(), e);
        }
    }
}

 

转载于:https://www.cnblogs.com/allenwas3/p/8352157.html

<think>嗯,用户想了解如何在Dubbo中实现自定义Filter。首先,我需要回忆一下Dubbo的Filter机制。Dubbo的Filter可以拦截RPC调用,进行各种处理,比如日志、鉴权、限流等。用户可能希望自己添加一些逻辑,比如记录访问日志或者权限验证。 根据系统指令,我需要确保回答结构清晰,分步骤说明。首先应该介绍实现自定义Filter的步骤,然后给出示例代码,再说明配置方式。还要注意引用中的资料,比如引用3提到扩展自定义过滤器,引用4提到Filter的应用场景,比如参数校验、认证授权等。 用户可能需要具体的代码示例,所以应该提供一个实现Filter接口的类,比如实现org.apache.dubbo.rpc.Filter接口,并重写invoke方法。然后配置这个Filter,可以通过XML或者注解方式。引用2中的XML配置例子<dubbo:filter ref="rbacAuthFilter"/>可以作为参考。 还要注意Dubbo的Filter生效范围,是服务提供者还是消费者端,或者同时配置。可能需要提醒用户如果要在全局生效,需要在consumer和provider都配置,如引用1中的配置consumerfilter列表。 另外,用户可能关心如何确保自定义Filter被正确加载,需要提到META-INF/dubbo/org.apache.dubbo.rpc.Filter文件中的配置,这点在引用3中有类似的自定义扩展说明。 可能还需要提到@Activate注解的使用,指定group为provider或consumer,这样Dubbo会自动激活对应的Filter。同时,需要确保依赖的版本兼容性,如引用5提到的版本问题,避免因版本不匹配导致类找不到的问题。 最后,生成相关问题时要围绕自定义Filter的实现、配置、应用场景、调试和生效范围等方面,帮助用户进一步了解相关知识。</think>### 如何在Dubbo中实现自定义Filter #### 一、实现步骤 1. **定义Filter类** 继承`org.apache.dubbo.rpc.Filter`接口并实现`invoke`方法,通过`@Activate`注解指定生效场景(服务提供方/消费方): ```java import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.rpc.*; @Activate(group = {"provider", "consumer"}) // 同时作用于服务提供方和消费方 public class CustomFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { System.out.println("请求参数: " + Arrays.toString(invocation.getArguments())); Result result = invoker.invoke(invocation); // 执行后续调用链 System.out.println("响应结果: " + result.getValue()); return result; } } ``` 2. **SPI配置** 在`META-INF/dubbo/org.apache.dubbo.rpc.Filter`文件中注册Filter(需UTF-8编码): ```text customFilter=com.example.CustomFilter ``` 3. **XML配置方式** 在服务提供方或消费方的Spring配置中显式声明(可选): ```xml <!-- 单服务生效 --> <dubbo:service interface="com.example.DemoService" filter="customFilter" /> <!-- 全局生效 --> <dubbo:provider filter="customFilter"/> <dubbo:consumer filter="customFilter"/> ``` #### 二、核心机制 - **Filter链式调用**:Dubbo通过责任链模式组织多个Filter,执行顺序由`@Activate`的`order`参数控制(值越小优先级越高) - **上下文透传**:通过`RpcContext.getContext()`可获取或修改请求上下文参数,实现跨Filter数据传递 - **异常处理**:在Filter中捕获`RpcException`可实现统一错误码转换或熔断逻辑 #### 三、典型应用场景 1. **安全控制** ```java public Result invoke(Invoker<?> invoker, Invocation invocation) { String token = invocation.getAttachment("authToken"); if (!validateToken(token)) { throw new RpcException("鉴权失败"); } return invoker.invoke(invocation); } ``` 2. **性能监控** 统计接口耗时并上报监控系统: ```java long start = System.currentTimeMillis(); Result result = invoker.invoke(invocation); long cost = System.currentTimeMillis() - start; Metrics.report(invocation.getMethodName(), cost); ``` #### 四、注意事项 1. **版本兼容性**:不同Dubbo版本对Filter的加载机制有差异,需参考官方文档[^5] 2. **资源释放**:在Filter中创建的资源(如数据库连接)需在`result.whenCompleteWithContext()`中确保释放 3. **配置覆盖**:服务级配置会覆盖全局配置,可通过`<dubbo:reference filter="-default" />`禁用默认Filter链 [^1]: Dubbo官方文档建议通过`filter`参数显式指定生效范围 [^3]: Filter扩展需遵循SPI机制规范 [^4]: 自定义Filter应避免阻塞操作以保证调用链路性能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值