Filter过滤器

本文介绍了Dubbo的反过滤器机制,它类似servlet的Filter,是递归链式调用。以CacheFilter为例说明可在invoke方法记录接口调用日志。关键代码在ProtocolFilterWrapper中,采用装饰器模式将Filter组装成链,且Dubbo以Invoker为主体包装Filter串成链。

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

Dubbo提供反过滤器应该类似servlet中我们经常用到的Filter,是一种递归的链式调用,用来在远程调用真正执行的前后加入一些逻辑。

@SPI
public interface Filter {
 
    /**
     * do invoke filter.
     * <p>
     * <code>
     * // before filter
     * Result result = invoker.invoke(invocation);
     * // after filter
     * return result;
     * </code>
     *
     * @param invoker    service
     * @param invocation invocation.
     * @return invoke result.
     * @throws RpcException
     * @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation)
     */
    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
 
}

看一个Filter的实现类CacheFilter,简单来说就是在invoke方法中记录一下接口调用的相关日志。

@Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.CACHE_KEY)
public class CacheFilter implements Filter {

    private CacheFactory cacheFactory;

    public void setCacheFactory(CacheFactory cacheFactory) {
        this.cacheFactory = cacheFactory;
    }

    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (cacheFactory != null && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.CACHE_KEY))) {
            Cache cache = cacheFactory.getCache(invoker.getUrl().addParameter(Constants.METHOD_KEY, invocation.getMethodName()));
            if (cache != null) {
                String key = StringUtils.toArgumentString(invocation.getArguments());
                if (cache != null && key != null) {
                    Object value = cache.get(key);
                    if (value != null) {
                        return new RpcResult(value);
                    }
                    Result result = invoker.invoke(invocation);
                    if (!result.hasException()) {
                        cache.put(key, result.getValue());
                    }
                    return result;
                }
            }
        }
        return invoker.invoke(invocation);
    }

}

接下来我们看一下所有的Filter是如果被调用的,关键代码在ProtocolFilterWrapper中,采用装饰器模式,在调用所有协议会执行ProtocolFilterWrapper这个类,这样就给我们实现Filter相关的机制提供了帮助,在ProtocolFilterWrapper中会将所有的Filter组装成一个链,当链中所有节点运行完之后才会真正执行最终的Invoker。

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;
		//获取所有的相关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);
                final Invoker<T> next = last;
				//创建Filter的执行链,当所有的Filter执行完毕之后再执行invoker
                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方法
                    public Result invoke(Invocation invocation) throws RpcException {
                        return filter.invoke(next, invocation);
                    }
 
                    public void destroy() {
                        invoker.destroy();
                    }
 
                    @Override
                    public String toString() {
                        return invoker.toString();
                    }
                };
            }
        }
		//返回的一个带有Filter链的invoker
        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();
    }
 
}

Dubbo这里的Filter设计的确很巧妙,它的目的是在Invoker调用前或后执行一系列Filter。按照常规思路,一般会这么写:

public class AFilter implements Filter {

	private Filter next = null;
 
	@Override
	public Result operator(Invoker invoker) {
	  // do something
	  Result res = null;
	  if (next != null) {
				res = next.operator(invoker);
		}else{
		    res = invoker.invoke(inv)
		}
    // do something
    return res;
	}
 
	@Override
	public void addFilter(Filter f) {
		next = f;
	}
}

这种思路下,是Filter为主体,串成调用链,但是Dubbo中却是转向使用Invoker为主体,包装住Filter,然后串成链:

public class InvokerWrapper {

    public Invoker buildInvokerChain(Invoker invoker, Filter filter){
        return new Invoker(){
            @Override
            public String invoke(String a) {
                return filter.operator(invoker);
            }
        };
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值