JAVA的SPI机制
参看文章:https://blog.csdn.net/piqianming/article/details/88931313
在分析dubbo spi机制之前有如下两个问题:
- 如何更加友好的支持功能的扩展?
- dubbo既然是微内核+插件的方式,具体是怎么体现的呢?
DUBBO SPI的实现以及运用
很显然,JAVA原生的SPI机制存在着一定的使用局限性。无法和主流的框架兼容。另外,JAVA SPI在使用时,ServiceLoader会加载指定目录下的所有的接口的实现,这样因为很多接口并未使用,造成资源的浪费。
我们以LoadBalance使用说明DUBBO在SPI机制的使用方式
@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {
/**
* select one invoker in list.
*
* @param invokers invokers.
* @param url refer url
* @param invocation invocation.
* @return selected invoker.
*/
@Adaptive("loadbalance")
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}
从接口中可以看到@SPI的注解以及设置了默认的值:随机负载均衡机制。另外在select方法上又加了@Adaptive("loadbalance")的注解。
- 扩展点(Extension Point)
扩展点:一个JAVA的接口,如LoadBalance就是一个接口。接口上方加了SPI的注解,DUBBO的ExtentionLoader工具类可以加载这个扩展点的实现。
-
扩展(Extension)
扩展:扩展点接口的实现,比如LoadBalance实现的接口:ConsistentHashLoadBalance,LeastActiveLoadBalance等。
-
扩展实例(Extension Instance)
扩展实例:扩展的实例
-
扩展自适应实例(Extension Adaptive Instance) 或者直接理解为代理类实例
扩展实例是自动生成的代理。其实就可以这么理解,在初始化的时候,因为没有invoke,因此并不知道负载均衡的实际机制。那么这个时候,先生成一个代理,当真正调用时,会根据参数决定调用ConsistentHashLoadBalance的扩展实例,还是LeastActiveLoadBalance的实例。
那么问题来了,怎么加载扩展呢?去哪里加载呢?
刚才在上边提到了一个类ExtentionLoader,他就是用来加载扩展的。我们知道LoadBalance的SPI注解有一个默认值。那么这个默认值"random"使用来做啥的?random可以认为是扩展的key,value就是扩展的全路径。放在指定的一些目录中。这些目录是META-INF下。如下图:
默认的扩展点实现方式配置文件目录:
讲到这里基本上,DUBBO的扩展机制就已经差不多了。其中还有一个注解@Adaptive。
设想一个场景:当A扩展中有一个属性B,而恰好B也是一个扩展。但是在A加载的时候,必须要要等待得调用的时候,才会知道
DUBBO的SPI和JAVA的SPI异同