(SPI)2.dubbo spi
一、dubbo spi效果简单描述
比如,你写了一个工具jar包,为了方便扩展,代码里以接口的方式调用,没有具体的实现类,下层应用只需要再mate-inf里以key-value对的形式指定好具体的实现类,然上层应用depend一下就能以这个实现类运行,达到很好的扩展性效果。
一、dubbo为什么要自己实现spi呢?
1、因为,dubbo需要一个接口提供多个实现类,然后通过注解的方式或者其他方式,指定使用哪个实现类,而java se 的spi不是key-value对的形式。
比如,它的/META_INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件内容是:
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
http=com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
以properties的方式,对实现类提供了一个标识符,然后通过@SPI("dubbo")这样的方式,实现加载指定的实现类,而这个方式,是java自带的spi做不到的。
2、dubbo的spi有adapter spi来达到根据不同参数使用不同实现类的动态效果,有activate根据不同条件获取不同实现类的效果。这些丰富的效果是javase spi不具备的。
3、dubbo的spi的ExtendsionFactory就是基于jdk的spi的。
4、dubbo的spi,按需实例化,不想jdk的全部实例化。
5、dubbo的spi有ioc的功能。
二、dubbo spi的三种
1.普通的获取扩展类。
Protocol dubbo = ExtensionLoader.getExtensionLoader(Protocol.class)
.getExtension("dubbo");
@SPI("dubbo")
public interface Protocol
在指定目录下(dubbo会扫描3个目录)添加指定规则的文件,描述接口的各个实现类
/META_INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
2.自适应扩展点
通过如下方式获取自适应扩展接口实现类。
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
有两种:
1)@Adaptive 加在类上。显示指定这个类是自适应类,通过getAdaptiveExtension方法获取到的就是这个类。
2)@Adaptive加在方法上。dubbo会产生一个代理类(默认是javasisit动态编码产生)。getAdaptiveExtension方法获取到的就是这个代理类。代理类会根据传参,通过URL参数动态决定调用哪一个实现类的这个方法。
@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
void destroy();
}
3.自动激活扩展点
能够根据传参,来指定具体激活获取到哪些实现类。
@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
public class CacheFilter implements Filter
自动激活扩展点可以根据url参数,指定加载激活哪些实现类。
activate有两个条件指定,1.group。可以是consumer、provider。2.value。
调用方式:
ExtensionLoader<Filter> loader = ExtensionLoader.getExtensionLoader(Filter.class);
/*
URL url = new URL("", "", 0);
url = url.addParameter("cache", "123");
// 参数url中有cache这个key,这里就能获取到CacheFilter
List<Filter> filters = loader.getActivateExtension(url, "zhangsan");
*/
URL url = new URL("", "", 0);
url = url.addParameter("ab", "cache");
// 传参ab,会根据这个参数,从url中获取具体的值,得到cache,所以这里也能获取到cacheFilter
List<Filter> filters = loader.getActivateExtension(url, "ab");
System.out.println(filters);
System.out.println(filters.size());
4.题外话
javasisit只是编译和加载,不能重新加载类,所以不能达到:
@ApiOperator("name")
@NotBlank("name不能魏空")
@Length(max = 20, value = "name不能超过20")
替换为
@MyNotBlankLengthApi("name", max = 40)
的效果。
从ExtensionLoader的源码中可以看出:
每个方法开头都会对参数进行合法性校验,而我实际开发中,为了代码简洁,减少if、else,往往会约定大于配置的那种思想,默认这个参数就是合法的,因为我觉得,代码都是自己写的,都是内部调用,代码文档也会说清楚,如果为了参数校验,增加很多if、else显得多余。但是dubbo是通用工具类,所以要做好这部分的配置。
(写出来的目的是,希望隔了很久之后,看了笔记还能回想起来)