JDK的spi和dubbo的spi
今天在学习dubbo的时候了解到dubbo的spi是模仿了JDK的spi,之前没有听说过spi这个东西,所以特地学习记录一下。SPI的全名为Service Provider Interface。我们在系统开发过程中不同模块之间一般都是用接口进行通信的。接口一般都有多个实现类。如果在模块里编码的时候涉及到了具体的实现类,则后续需要修改实现类或者新增实现类的时候就要修改原来的模块编码,这样就违反了开闭原则(对扩展开发,对修改关闭。避免新增功能的时候修改原来的代码对原有的功能造成新的bug。)不利于代码的维护。JDK的SPI实现了为接口自动寻找实现类的功能。spi有点类似于ioc思想,将接口与实现类的装配转移到代码之外,用一个配置文件就能实现。
spi的使用方式:当服务提供者提供一个接口的多个实现的时候,一般会在META-INF/services/ 下面建立一个与接口全路径同名的文件,在文件里配置接口具体的实现类。当外部调用模块的时候的时候就能实例化对应的实现类。
mysql的代码里就用到了spi
jdk用来实现serviceloader来实现接口实现类的加载。
ServiceLoader实现了Iterable接口,所以当在一个文件里配置多个实现类的时候,会加载一组实现类进来。
定义一个command接口,建立一个配置文件,并在里面配置2个实现类。
加载的时候2个类都能加载进来
为什么dubbo不直接用jdk的spi机制,而是自己模仿实现了一个spi机制呢?
jdk的spi会在一次实例化所有实现,可能会比较耗时,而且有些可能用不到的实现类也会实例化,浪费资源而且没有选择。另外dubbo的spi增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其他扩展点。这是jdk spi不支持的。
dubbo的spi文件定义在META-INF/dubbo/internal/路径下面和jdk的spi类似。但是dubbo的spi文件里面格式和jdkSPI有点不一样,格式是扩展名=全路径的类名,比如
threadlocal=com.alibaba.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
lru=com.alibaba.dubbo.cache.support.lru.LruCacheFactory
jcache=com.alibaba.dubbo.cache.support.jcache.JCacheFactory
扩展名的作用是用来实现选择性的加载实现类。
dubbo的spi使用ExtensionLoader来实现。
//这个方法用户获取一个接口的ExtensionLoader public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { if (type == null) throw new IllegalArgumentException("Extension type == null"); if(!type.isInterface()) {
- throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
//这个方法通过扩展名获取一个实现类 public T getExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); if ("true".equals(name)) { return getDefaultExtension(); } Holder<Object> holder = cachedInstances.get(name); if (holder == null) { //创建一个holder放到map里面 putIfAbsent保证了只有一个能放进去 cachedInstances.putIfAbsent(name, new Holder<Object>()); holder = cachedInstances.get(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; }
private ExtensionLoader(Class<?> type) { this.type = type; //objectFactory的作用是为dubbo的IOC提供对象 objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
//获取一个扩展装饰类的对象 如果类没有用Adaptive注解就动态创建一个装饰类 public T getAdaptiveExtension() { //优先从缓存获取 Object instance = cachedAdaptiveInstance.get(); //双重判空的单例模式 if (instance == null) { if(createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try { instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { createAdaptiveInstanceError = t; throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t); } } } } else { throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } } return (T) instance; }