Dubbo-SPI
来源:互联网 发布:沙巴克传奇有哪些端口 编辑:程序博客网 时间:2024/05/17 07:56
SPI
1. 定义
SPI即Service Provider Interface,服务提供接口。
系统中抽象的各个模块,往往有很多不同的实现方案,比如日志模块,xml解析模块,jdbc模块的方案等。面向对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里设计具体的实现类,就违反了可插拔的原则,如果需要替换一种实现,就需要修改代码。
为了实现在模块装配的时候能不在程序里动态指明,就需要一种服务发现机制。JAVA SPI就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将转配的控制权一到程序之外,在模块化设计中这个机制尤其重要。
1.1. Java SPI的约定
当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/
目录里同事创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过jar包META-INF/services
里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样一个约定就能很好的找到接口的实现类,而不需要在代码里定制。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader
。
1.2. 范例
1.3. Demo
定义接口类
package cn.test.spi;public interface Animal { String cry();}
接口实现类
package cn.test.spi;public class Cat implements Animal { public String cry() { return "cat cry..."; }}public class Dog implements Animal { public String cry() { return "dog cry..."; }}
运行
package cn.test.spi;import java.util.Iterator;import java.util.ServiceLoader;public class TestAnimal { public static void main(String[] args) { ServiceLoader<Animal> loader = ServiceLoader.load(Animal.class); Iterator<Animal> iterator = loader.iterator(); while (iterator.hasNext()) { Animal animal = iterator.next(); System.out.println(animal.getClass()); System.out.println(animal.cry()); } }}
其中,在META-INF/services目录中创建文件cn.test.spi.Animal
,内容为cn.test.spi.Cat
;
输出结果为:
class cn.test.spi.Catcat cry...
以上及时基于Java SPI机制查找服务的实现。
2. Dubbo基于SPI思想实现
Dubbo对Java SPI发现机制加强而来。
- Java SPI标准的SPI会一次性实例化扩展点的所有实现,如果扩展实现很耗时,但如果没有用到也加载,会资源;还有如果实现类缺失依赖,实例化直接出错;
- 如果扩展点记载失败,连扩展点的名称都拿不到;
- 增加了IOC的支持,一个扩展点可以直接setter注入其他扩展点;
优先关注dubbo-common
子项目的com.alibaba.dubbo.common.extension
类包。
2.1. SPI接口定义
Dubbo定义了注解@SPI用于扩展,只要在接口上打了@SPI注解的接口才会去找找扩展点实现。
配置信息会从以下几个位置读取扩展信息:
- META-INF/dubbo/internal/
- META-INF/dubbo/
- META-INF/services/
以com.alibaba.dubbo.rpc.ProxyFactory
为例:
@SPI("javassist")public interface ProxyFactory { @Adaptive({Constants.PROXY_KEY}) <T> T getProxy(Invoker<T> invoker) throws RpcException; @Adaptive({Constants.PROXY_KEY}) <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;}
2.2. ExtensionLoader类解析
每个定义SPI的接口都会构建一个
ExtensionLoader
实例,存储在ExtensionLoader.EXTENSION_LOADERS
属性中。
// 触发入口public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { // check ... 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;}// 构建ExtensionLoader对象private ExtensionLoader(Class<?> type) { this.type = type; // 当type不是ExtensionFactory类型时,寻找ExtensionFactory对象, // 赋值给ExtensionLoader的objectFactory,为了之后IOC寻找依赖对象时使用; // 由此可以看出,如果使用dubbo的SPI,第一个初始化的就是ExtensionFactory扩展节点; // 下节通过动态扩展ExtensionFactory节点来了解代码运行轨迹; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());}
2.3. 加载流程
提供由SPI扩展对象依赖属性的查找入口。
// 当clazz不是ExtensionFactory.clss,第一个调用触发ExtensionLoader<ExtensionFactory>对象初始化;ExtensionLoader.getExtensionLoader(clazz);private ExtensionLoader(Class<?> type) { this.type = type; // getAdaptiveExtension方法触发初始化; // 通过该方法获得指定类型的代理对象,并非实际的业务处理对象; // PS:代理对象生成:1、自建[通过@Adaptive标识];2、动态代理 objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());}// 创建动力扩展对象private T createAdaptiveExtension() { try { // 1. getAdaptiveExtensionClass() 获取代理对象class // 2. 对指定代理class实例化 // 3. 代理对象如有依赖,可从SPI上下文找到,通过setter方式植入 return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e); }}// 获取代理对象classprivate Class<?> getAdaptiveExtensionClass() { // 通过配置文件获取扩展点 实现类 getExtensionClasses(); // 初始化时,如果有指定代理对象class,直接返回 if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } // 初始化时,如果并没有指定代理对象class,运行时通过字节码方式动态生成class return cachedAdaptiveClass = createAdaptiveExtensionClass();}// 加载扩展实现类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;}// 加载扩展实现类private Map<String, Class<?>> loadExtensionClasses() { final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { String value = defaultAnnotation.value(); if (value != null && (value = value.trim()).length() > 0) { String[] names = NAME_SEPARATOR.split(value); if (names.length > 1) { throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); } if (names.length == 1) cachedDefaultName = names[0]; } } Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); // 加载文件 META-INF/dubbo/internal/{type.getName()} loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY); // 加载文件 META-INF/dubbo/{type.getName()} loadFile(extensionClasses, DUBBO_DIRECTORY); // 加载文件 META-INF/services/{type.getName()} loadFile(extensionClasses, SERVICES_DIRECTORY); return extensionClasses;}// 在初始后,并没有找到指定的代理class,则动态生成;private Class<?> createAdaptiveExtensionClass() { // 生成class的string值 String code = createAdaptiveExtensionClassCode(); ClassLoader classLoader = findClassLoader(); // 获取Compiler对象 com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); // 将生成的code,以及compiler,加载 return compiler.compile(code, classLoader);}
从下面截图可以获悉:Compiler
的扩展类有三个,分别为:com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler
,com.alibaba.dubbo.common.compiler.support.JdkCompiler
,com.alibaba.dubbo.common.compiler.support.JavassistCompiler
。其中代理类为:AdaptiveCompiler
。
实际执行轨迹为:由于属性name
为空,会通过loader.getDefaultExtension()
,获取默认的扩展实现类。
public T getDefaultExtension() { getExtensionClasses(); // 获取默认的扩展实现的名字, 而默认扩展实现的名字有getExtensionClasses()方法执行获得; if (null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName)) { return null; } return getExtension(cachedDefaultName);}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;}// 此方法已经getExtensionClasses方法同步过。private Map<String, Class<?>> loadExtensionClasses() { // 从SPI标签的value获取 final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { String value = defaultAnnotation.value(); if (value != null && (value = value.trim()).length() > 0) { String[] names = NAME_SEPARATOR.split(value); if (names.length > 1) { throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); } if (names.length == 1) cachedDefaultName = names[0]; } }... // 代码省略}// Compiler的接口代码如下:// 因此,Dubbo默认使用javasisist字节码类库@SPI("javassist")public interface Compiler { Class<?> compile(String code, ClassLoader classLoader);}
2.4. IOC
动态注入属性值
injectExtension
两个地方调用:
createExtension(String name)
createAdaptiveExtension()
private T injectExtension(T instance) { try { // objectFacatory 为ExtensionFactory的代理对象;即:AdaptiveExtensionFactory if (objectFactory != null) { for (Method method : instance.getClass().getMethods()) { // 通过set方法动态注入属性 if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { Class<?> pt = method.getParameterTypes()[0]; try { String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; // 通过objectFacatory的getExtension获取属性值; Object object = objectFactory.getExtension(pt, property); if (object != null) { // set属性值 method.invoke(instance, object); } } catch (Exception e) { logger.error("fail to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance;}
下面看下AdaptiveExtensionFactory
处理逻辑:
@Adaptivepublic class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() { //实例化AdaptiveExtensionFactory时候,会将所有的扩展点对象放入factories属性中; 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); } // 查找执行上下文对象的时候,会按照放入factories对象的顺序; // 以此从扩展点对象获取,直至找到位置; 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; }}
- Dubbo-SPI
- dubbo spi--实现细节
- dubbo SPI机制
- dubbo spi原理解析
- dubbo基于spi扩展
- dubbo-spi扩展一
- dubbo-spi扩展二
- dubbo之SPI解析
- Dubbo SPI机制简介
- Dubbo的SPI实现
- java spi与dubbo spi区别
- java spi与dubbo spi区别
- dubbo源码之SPI注解
- dubbo spi extensionloader 插件化
- Dubbo源码 SPI实现ExtensionLoader
- DUBBO SPI部分源码浅析
- Dubbo入门学习--SPI实现@SPI和@Adaptive
- 第一章 Dubbo风格的SPI-ExtensionLoader
- arm汇编—str指令
- iPhone X 的凹槽 和 iOS 11 中一些相关 CSS 属性
- Failed to read auto-increment value from storage engine
- idea配置SpringBoot热部署
- Java小代码(可直接用)
- Dubbo-SPI
- Caused by: org.apache.ibatis.builder.BuilderException: Error resolving class . Cause: org.apache.iba
- Node.js学习笔记(1)
- js学习
- dataguard日常操作
- mysql命令大全(速成版)
- DNX SDK版本 “dnx-clr-win-x86.1.0.0-beta5”无法安装
- 欢迎使用CSDN-markdown编辑器
- Android OpenGL教程-第六课【转】