dubbo内核spi机制

Java SPI

Java SPI策略模式,具体实现步骤:

 (1) 定义一个接口及对应的方法
 (2) 编写接口的实现类、
 (3) 在META-INF/services/目前下,创建一个以接口全路径命名的文件,如com.test.spi.PrintService
 (4) 文件内容为具体实现类的全路径名,如果有多个,则用分隔符分离
 (5) 在代码中通过java.util.ServiceLoader来加载具体实现类

代码
com.test.spi.PrintService

// SPI接口定义
public interface PrintService {
	void printInfo();
}

SPI接口实现类

public class PrintServiceImpl implements PrintService {
	@Override
	public void printInfo() {
		System.out.println("Hello world");
	}
}

SPI具体实现机制

public static void main(String[] args) {
	ServiceLoader<PrintService> serviceLoader = ServiceLoader.load(PrintService.class);
	for(PrintService printService : serviceLoader) {
		printService.printInfo();
	}
}

Java SPI不总:

  • JDK标准的SPI会一次性实例化扩展点所有的实现,如果有扩展点没有,也会加载,资料浪费
  • 如果扩展点加载失败,会导致调用方报错,而且这个错误很难定位到是这个原因。如JDK标准的ScriptEngine,通过getName()获取脚本名称,如果RubyScriptEngine因为所依赖的jruby.jar不存在,导致加载失败,当用户执行Ruby脚本,会报不支持Ruby,而不是真正失败的原因
  • 没有对扩展IOC和AOP的支持

Dubbo SPI

  • 扩展接口,需要@SPI标记
  • resouce目录下配置META-INF/dubbo或者META-INF/dubbo/internal并基于SPI接口创建一个文件
    在这里插入图片描述
    Dubbo 针对的扩展点非常多,可以针对协议、拦截、集群、路由、负载均衡、序列化、容器… 几乎里面用到的所有功能,都可以实现自己的扩展

org.apache.dubbo.common.extension.ExtensionLoader

 * @see org.apache.dubbo.common.extension.SPI
 * @see org.apache.dubbo.common.extension.Adaptive
 * @see org.apache.dubbo.common.extension.Activate
 */
public class ExtensionLoader<T> {
    private static final String SERVICES_DIRECTORY = "META-INF/services/";
    private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
    private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
	/** 全局缓存 扩展类和对应的扩展加载器缓存*/
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
	/** 全局缓存 扩展类与类初始化后的实例*/
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
	/****************加载spi的扩展类的实例对象**********************/
	/**当前扩展点类*/
    private final Class<?> type;

    private final ExtensionFactory objectFactory;
	/**扩展类与扩展名缓存*/
    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
	/**普通扩展类缓存,不包括自适应扩展类和Wrapper类*/
    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
	/**扩展名与@Activate的缓存*/
    private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
    /** 扩展名与扩展实例对象缓存*/
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
    /** 实例化后的自适应(Adaptive)扩展对象,只能同时存在一个*/
    private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
    /**自适应扩展类缓存*/
    private volatile Class<?> cachedAdaptiveClass = null;
    /**默认扩展名 如@SPI("dubbo") 默认名dubbo*/
    private String cachedDefaultName;
    /** 存储自适应扩展点的异常错误*/
    private volatile Throwable createAdaptiveInstanceError;
    /**Wrapper类缓存*/
    private Set<Class<?>> cachedWrapperClasses;
	/** 存储加载异常*/
    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();
}

静态扩展点

LoadBalance loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension("random");
System.out.println(loadBalance); // RandomLoadBalance

META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance

random=org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
roundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
leastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
consistenthash=org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance

getExtension("random")

    1. 读取SPI对应的路径下的配置文件,根据配置加载所有的的扩展类并缓存(不进行初始化)
    1. 根据传入的名称初始化对应的扩展类
  • 3)尝试查找符合条的的包装类: 扩展点的Setter方法 如 setProtocol(Protocol protocol)方法会自动注入protocol的扩展点实现, 加载包装了Wrapper会加载(ProtocolFilterWrapper(protocol)
    1. 返回对应的实例

ExtensionLoader#getExtensionLoader 获取扩展类加载器实例

// 构造函数 实例化
 private ExtensionLoader(Class<?> type) {
        this.type = type;
        // 如果当前的 type=ExtensionFactory,type,那么 objectFactory=null, 否则会创建一个自适应扩展点给到 objectFacotry
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
  }
   public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
   		// 初始化ExtensionLoader
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

getExtension(name)根据实例获取扩展实例

  public T getExtension(String name) {
  		...
  		// 获取默认的扩展点 如 @SPI(RandomLoadBalance.NAME) random
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        final Holder<Object> holder = getOrCreateHolder(name);
        // 缓存一下,如果实例已经加载过了,直接从缓存中读取
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                	// 根据名称创建实例
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

createExtension根据名称创建扩展点

 private T createExtension(String name) {
 		// 获取 加载指定路径下 的扩展点文件 的扩展类
 		// getExtensionClasses 加载指定路径下的所有文件
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) { // 没有找到,则抛出异常
            throw findException(name);
        }
        try {
        	// 用chm保存实例,做缓存
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            // 实例注入 可用通过成员变量 进行依赖注入功能
            injectExtension(instance);
            // 如果配置包装扩展类,加载包装扩展类
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }

getExtensionClasses
这个方法会查找指定目录META-INF/dubbo||META-INF/services下对应的type,加载定位扩展点,定位加载

  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;
    }
      /**
     * synchronized in getExtensionClasses
     * 加载配置文件过程
     * */
    private Map<String, Class<?>> loadExtensionClasses() {
       // 缓存默认实现 如@SPI("random") ->random
        cacheDefaultExtensionName(); 
        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // 加载路径下面的SPI配置文件
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
		.. 
        return extensionClasses;
    }
	
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
        String fileName = dir + type;
        try {
            Enumeration<java.net.URL> urls;
            ClassLoader classLoader = findClassLoader();
            // 通过getResouces或getSystemResources得到配置文件
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) { 
           	    // 循环遍历urls,解析字符串,得到扩展实现类,并加入缓存
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

Set注入

dubbo的SPI 实现了通过Set方法注入,需要满足一下条件:

  • 当前扩展点中依赖其他扩展点
  • set方法进行依赖注入
 Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("registry");
 System.out.println(protocol);

Protocol配置文件

filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
http=org.apache.dubbo.rpc.protocol.http.HttpProtocol
rmi=org.apache.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=org.apache.dubbo.rpc.protocol.hessian.HessianProtocol
http-invoker=org.apache.dubbo.rpc.protocol.httpinvoker.HttpInvokerProtocol
org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocol
native-thrift=org.apache.dubbo.rpc.protocol.nativethrift.ThriftProtocol
memcached=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=org.apache.dubbo.rpc.protocol.redis.RedisProtocol
rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol
xmlrpc=org.apache.dubbo.xml.rpc.protocol.xmlrpc.XmlRpcProtocol
registry=org.apache.dubbo.registry.integration.RegistryProtocol
qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper
public class RegistryProtocol implements Protocol {
     private Cluster cluster;
     private Protocol protocol;
     ...
    public void setCluster(Cluster cluster) {
        this.cluster = cluster;
    }
    ...
    public void setProtocol(Protocol protocol) { // 会注入Protocol$Adapive
        this.protocol = protocol;
    }
}

RegistryProtocol
在这里插入图片描述
set注入源码

  • org.apache.dubbo.common.extension.ExtensionLoader#createExtension 调用injectExtension方法
 private T injectExtension(T instance) { 
 		// 这个不能为空,否则下一步不能获取注入的扩展点对象
        if (objectFactory == null) {
            return instance;
        }
        try {
        	// 获取实例对应的方法
            for (Method method : instance.getClass().getMethods()) {
            	// 判断是否是一个set方法
                if (!isSetter(method)) {
                    continue;
                }
                /**
                 * Check {@link DisableInject} to see if we need auto injection for this property
                 */
                 // 可以选择禁用依赖注入
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                // 获取的方法的参数,这个参数必须是一个对象类型并且是一个扩展点
                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }
                try { 
                	// 获取set方法中属性名字,根据属性名字进行加载
                    String property = getSetterProperty(method);
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) { 
                    	// 调用set方法进行赋值 
                        method.invoke(instance, object);
                    }
                } catch (Exception e) {
                    logger.error("Failed to inject via method " + method.getName()
                            + " of interface " + type.getName() + ": " + e.getMessage(), e);
                }

            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

org.apache.dubbo.common.extension.factory.SpiExtensionFactory#getExtension

	// 获取扩展点对象
    public <T> T getExtension(Class<T> type, String name) {
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { 
        	// 根据类型获取扩展点加载类
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            if (!loader.getSupportedExtensions().isEmpty()) {
            	// 获取自适应扩展类 Protocol$Adaptive
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }

Wrapper包装类

  Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo");
        System.out.println(protocol);// QosProtocolWrapper(ProtocolListenerWrapper(ProtocolFilterWrapper(DubboProtocol))

在这里插入图片描述
缓存包装类

  • org.apache.dubbo.common.extension.ExtensionLoader#loadClass 调用cacheWrapperClass 将相应的包装类缓存到ExtensionLoader中的成员变量 cachedWrapperClasses
 // org.apache.dubbo.common.extension.ExtensionLoader#loadClass 
 // 以Protocol为例,这里加载配置org.apache.dubbo.rpc.protocol中含有Wrapper结尾的包装类
 // 缓存 ProtocolFilterWrapper,ProtocolListenerWrapper,QosProtocolWrapper
 else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
}
..
private void cacheWrapperClass(Class<?> clazz) {
      if (cachedWrapperClasses == null) {
          cachedWrapperClasses = new ConcurrentHashSet<>();
      }
      cachedWrapperClasses.add(clazz);
  }

创建扩展类是增强
org.apache.dubbo.common.extension.ExtensionLoader#createExtension

  // 以protocol为类,这里 WrapperClassess 为 ProtocolFilterWrapper,ProtocolListenerWrapper,QosProtocolWrapper
  Set<Class<?>> wrapperClasses = cachedWrapperClasses;
  if (CollectionUtils.isNotEmpty(wrapperClasses)) {
      for (Class<?> wrapperClass : wrapperClasses) { 
      	 // wrapperClass.getConstructor 调用扩展类的构造方法进行增强
          instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
      }
  }

最终结果QosProtocolWrapper(ProtocolListenerWrapper(ProtocolFilterWrapper(DubboProtocol)

注意: wrapper类的包装顺序不是以配置文件的中先后为绝对属性,因为存储包装类的容器是ConcurrentHashSetConcurrentHashSet又是以new ConcurrentHashMap<E, Object>()的key实现的。
包装类是某一方面的功能功能增强,无所谓顺序,不想filter

Adaptive 自适应扩展点

Compiler compiler=ExtensionLoader.getExtensionLoader(Compiler.class).getAdaptiveExtension();
System.out.println(compiler.getClass());

AdaptiveCompiler 这个类有一个注解@Adaptive,这个就是一个自适应扩展点的标识。它可以修饰在类上,也可以修饰在方法上面。

放在类上,说明当前类是一个确定的自适应扩展点的类。如果是放在方法级别,那么需要生成一个动态字节码,来进行转发

修饰类上

在这里插入图片描述
修饰类上:
org.apache.dubbo.common.compiler.support.AdaptiveCompiler

 @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        // 最终还是如静态扩展点getExtension("jdk")
        if (name != null && name.length() > 0) {
            compiler = loader.getExtension(name);
        } else {
            compiler = loader.getDefaultExtension();
        }
        return compiler.compile(code, classLoader);
    }

org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
objectFactory
在获得 ExtensionLoader 的时候,就对 objectFactory 进行了初始化

 private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

然后通过 ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()去获得一个自适应的扩展点,进
入 ExtensionFactory 这个接口中,可以看到它是一个扩展点,并且有一个自己实现的自适应扩展点 AdaptiveExtensionFactory;
在这里插入图片描述
除了自定义的自适应适配器类以外,还有两个实现类,一个是 SPI,一个是 Spring,AdaptiveExtensionFactory
AdaptiveExtensionFactory 轮询这 2 个,从一个中获取到就返回

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
    private final List<ExtensionFactory> factories; 
    public AdaptiveExtensionFactory() {
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }
    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

修饰在方法

修饰在方法上,需要在动态字节码

@SPI("dubbo")
public interface Protocol {
 @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
}

基于方法层面的@Adaptive,基本实现原理的图
在这里插入图片描述
getAdaptiveExtension
这个方法主要就是要根据传入的接口返回一个自适应的实现类

   public T getAdaptiveExtension() {
   		//cacheAdaptiveInstance,
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " +
                        createAdaptiveInstanceError.toString(),
                        createAdaptiveInstanceError);
            }
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                    	// 创建一个自适应扩展点的实现
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }
        return (T) instance;
    }

创建一个自适应扩展点的实现
这个方法中做两个事情

  1. 获得一个自适应扩展点实例
  2. 实现依赖注入
private T createAdaptiveExtension() {
        try {
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

getAdaptiveExtensionClass

  private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
  }

createAdaptiveExtensionClass

private Class<?> createAdaptiveExtensionClass() { 
		// 这里是动态生成代理类 如 Protocol$Adaptive
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        ClassLoader classLoader = findClassLoader();
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

Protocol$Adaptive
动态生成的代理类,以下是我通过 debug 拿到的代理类

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
         // 最终还是回到调用静态扩展点   
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
}

Activate激活扩展点

自动激活扩展点,有点类似 springboot 的时候用到的 conditional,根据条件进行自动激活。但是这里设计的初衷是,对
于一个类会加载多个扩展点的实现,这个时候可以通过自动激活扩展点进行动态加载, 从而简化配置我们的配置工作
@Activate 提供了一些配置来允许我们配置加载条件,比如 group 过滤,比如 key 过滤

举个例子,我们可以看看 org.apache.dubbo.Filter 这个类,它有非常多的实现,比如说 CacheFilter,这个缓存过滤器,配置信息
如下

cache=org.apache.dubbo.cache.filter.CacheFilter
validation=org.apache.dubbo.validation.filter.ValidationFilter
echo=org.apache.dubbo.rpc.filter.EchoFilter
generic=org.apache.dubbo.rpc.filter.GenericFilter
genericimpl=org.apache.dubbo.rpc.filter.GenericImplFilter
token=org.apache.dubbo.rpc.filter.TokenFilter
accesslog=org.apache.dubbo.rpc.filter.AccessLogFilter
activelimit=org.apache.dubbo.rpc.filter.ActiveLimitFilter
classloader=org.apache.dubbo.rpc.filter.ClassLoaderFilter
context=org.apache.dubbo.rpc.filter.ContextFilter
consumercontext=org.apache.dubbo.rpc.filter.ConsumerContextFilter
exception=org.apache.dubbo.rpc.filter.ExceptionFilter
executelimit=org.apache.dubbo.rpc.filter.ExecuteLimitFilter
deprecated=org.apache.dubbo.rpc.filter.DeprecatedFilter
compatible=org.apache.dubbo.rpc.filter.CompatibleFilter
timeout=org.apache.dubbo.rpc.filter.TimeoutFilter
trace=org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter
future=org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter
monitor=org.apache.dubbo.monitor.support.MonitorFilter

metrics=org.apache.dubbo.monitor.dubbo.MetricsFilter
ExtensionLoader<Filter> loader=ExtensionLoader.getExtensionLoader(Filter.class); 
URL url=new URL("","",0); 
// url=url.addParameter("cache","cache"); 有和没有的区别
List<Filter> filters=loader.getActivateExtension(url,"cache"); 
System.out.println(filters.size());

group 表示客户端和和服务端都会加载,value 表示 url 中有 cache_key 的时候

@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
public class CacheFilter implements Filter {
	... 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值