Dubbo Filter

897 阅读4分钟

前言

Dubbo的Filter实现入口是在ProtocolFilterWrapper,因为ProtocolFilterWrapper是Protocol的包装类,所以会在加载的Extension的时候被自动包装进来,实现在ProtocolFilterWrapper.buildInvokerChain方法

源码解析

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()) {
            //构建filter调用链
            for (int i = filters.size() - 1; i >= 0; i--) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

                    @Override
                    public Class<T> getInterface() {
                        return invoker.getInterface();
                    }

                    @Override
                    public URL getUrl() {
                        return invoker.getUrl();
                    }

                    @Override
                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }

                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
                        return filter.invoke(next, invocation);
                    }

                    @Override
                    public void destroy() {
                        invoker.destroy();
                    }

                    @Override
                    public String toString() {
                        return invoker.toString();
                    }
                };
            }
        }
        return last;
    }
  1. 获得所有符合条件的Filter(已经排好序的)
  2. 构建filter调用链

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

public List<T> getActivateExtension(URL url, String key, String group) {
        //key service.filter
        //获取该service自定义filter,以逗号隔开
        String value = url.getParameter(key);
        return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
    }
public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<T>();
        //自定义filter数组
        List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        //如果自定义filter包含"-default"就不会加载dubbo自带的filter
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            //通过ExtensionLoader获取所有的filter
            getExtensionClasses();
            //遍历具有Activate注解的,这个cachedActivates是在getExtensionClasses()中放入的
            //dubbo自带的filter都是Activate注解的,不需要手动在配置文件中加入这些filter,
            //如果自己也想写全局的,也可以加上Activate注解,这样也会出现在cachedActivates中
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                //判断是否符合条件 是否在该组中,分为provider和consumer
                if (isMatchGroup(group, activate.group())) {
                    //得到该filter实例
                    T ext = getExtension(name);
                    if (!names.contains(name)
                            && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                            && isActive(activate, url)) {
                        //如果自定义filter不包含该filter,
                        //并且自定义filter不包含“-”+该filter,并且isActive就放入exts中
                        //这里如果不想用dubbo自带的某个filter就可以用“-”+filter名称去除掉
                        exts.add(ext);
                    }
                }
            }
            //对这些filter进行排序
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        List<T> usrs = new ArrayList<T>();
        //遍历自定义filter数组
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            //如果filter名称不以-开头并且filter数组不包含“-”+该filter名称
            if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
                    && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
                //如果该名称为default    
                if (Constants.DEFAULT_KEY.equals(name)) {
                    //如果exts不为空
                    if (!usrs.isEmpty()) {
                        //把usrs加入到exts中并放到前面,并清空usrs,
                        //这里和后面实现了自定义filter和dubbo自带的filter排序功能
                        //因为看后面最终返回的是exts(有序的)
                        //举例 filter="filter1,filter2,filter3,default,filter4"
                        //最终exts顺序就为filter1,filter2,filter3,dubbo符合条件的filter,filter4
                        //如果没有写default,dubbo自带的会在自定义的前面
                        exts.addAll(0, usrs);
        ,                usrs.clear();
                    }
                } else {
                    //如果不包含就放入usrs中
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        //变量完后,把usrs剩下的都放到exts中
        if (!usrs.isEmpty()) {
            exts.addAll(usrs);
        }
        
        return exts;
    }
private Map<String, Class<?>> getExtensionClasses() {
        //从缓存中获取
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    //如果没有就从文件中加载
                    classes = loadExtensionClasses();
                    //放到缓存中
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
    
private Map<String, Class<?>> loadExtensionClasses() {
        //获取该类型的SPI默认值
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if ((value = value.trim()).length() > 0) {
                String[] names = NAME_SEPARATOR.split(value);
                if (names.length > 1) {
                    throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                            + ": " + Arrays.toString(names));
                }
                //设置默认值
                if (names.length == 1) cachedDefaultName = names[0];
            }
        }
        
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        //META-INF/dubbo/internal/ 该文件下查找 com.alibaba.dubbo.rpc.Filter并加载
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        //META-INF/dubbo/ 该文件下查找 com.alibaba.dubbo.rpc.Filter
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        //META-INF/services/ 该文件下查找 com.alibaba.dubbo.rpc.Filter
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        //最终Map<String, Class<?>> extensionClasses
        return extensionClasses;
    }

使用和小结

综上源码解析,dubbo是采用自己的SPI机制,一个serviceBean会被很多层东西包装,其中包含ProtocolFilterWrapper
在转换为export的时候,会调用

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

构建filter链
dubbo的filter也是基于SPI机制,看上面代码可以看到他会去 META-INF/dubbo/internal/、META-INF/dubbo/、META-INF/services/ 该文件下查找 com.alibaba.dubbo.rpc.Filter并加载

  1. 我们要自定义filter 可以在resources下创建对应文件夹和文件,然后在对应的service上面加上filter="hystrixFilter"
  2. 如果想把自己的filter变成dubbo自带的filter一样,可以在自己的filter类上加上@Activate注解,这样你就可以认为他是全局的filter了,就不需要在每个service中引入了
  3. 全局的filter可以用注解值 group区分是提供者和调用者这样就更加灵活使用全局的filter了,还可以用order进行排序
  4. 如果不想用所有dubbo自带的filter或者说全局的filter 可以用-default去除,如果不想用单个dubbo自带的filter,可以用“-”+filter名称去除
  5. filter排序,一般情况下自定义filter会在dubbo自带的filter后面,可以用filter="filter1,default,filter3"进行排序