1、平时遇到过的使用java的spi的例子
1)mysql的驱动
2)spring-web
2、spi的设计目标
面向对象的设计里,模块之间是接口编程,模块之间不对实现类进行硬编码,如果实现类写死在代码里,想要换一种实现,就需要修改代码,为了不在代码里写死,就需要一种服务的发现机制,为某个接口寻找服务实现的机制,有点类似ioc,将装配的控制权移交到代码之外
3、spi的约定
当一个接口有多个实现类的时候,一般在META-INF/services/目录下,创建接口的同名文件(接口的包名+文件名)
文件的内容就是接口的实现类的名称(包名+文件名)
而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类java.util.ServiceLoader
4、查找接口的实现通过ServiceLoader来完成
Iterator<UserService> services = ServiceLoader.load(UserService.class).iterator();
5、dubbo为什么要实现自己的spi,而不是用jdk的spi
1)jdk的spi会一次性实例化一个扩展点的所有实现,初始化会很耗时间,并且没有用到的实现也会加载,浪费资源
2)增加了对扩展点ioc和aop的支持,一个扩展点可以直接setter注入其他扩展点
6、dubbo的spi的约定
dubbo spi 在JAVA自带的SPI基础上加入了扩展点的功能,即每个实现类都会对应至一个扩展点名称,其目的是 应用可基于此名称进行相应的装配。这样就解决了jdk加载全部的实现类的缺点了。
dubbo spi 目录文件
dubbo spi 文件内容:
wanglu=wanglu.dubbo.server.WlFilter
装配自定义Filter
<dubbo:provider filter="wanglu" timeout="2000" retries="2" id="abc"></dubbo:provider>
7、dubbo的spi的源码解析
1)dubbo spi的目的:dubbo获取一个实现类的对象
2)通过ExtensionLoader实现spi扩展点的加载
途径:public T getExtension(String name)
实现途径:
getExtensionLoader(Class<T> type),作用就是为该Class<T>接口new一个ExtensionLoader,然后缓存起来。
getAdaptiveExtension() 获取一个扩展装饰类的对象,这个类有一个规则,如果他没有@Adaptive注解,就动态创建一个装饰类,例如: Protocol$Adaptive对象
getExtension(String name)获取一个对象
3)源码
---------------------------------------------------ExtensionLoader.getExtensionLoader(Class<T> type)
ExtensionLoader.getExtensionLoader(Container.class)
-->this.type = type;
-->objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-->ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-->this.type = type;
-->objectFactory = null;
执行以上的代码,完成了两个属性的初始化
1、每个ExtensionLoader都包含两个值type和objectFactory
<T> type //构造器初始化要得到的接口名
ExtensionFactory objectFactory 构造器,初始化时AdaptiveExtensionFactory【SpiExtensionFactory】
2、new 一个ExtensionLoader都存储在ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS
3、关于objectFactory的一些细节
objectFactory 就是ExtensionFactory 通过ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()来实现的,但是objectFactory 为空
objectFactory就是dubbo的IOC提供所有对象的