Dubbo 源码阅读 gitee:https://gitee.com/hitol/dubbo-source/tree/read_2.7.5/
Java SPI
SPI 是服务发现机制,为某个接口寻找服务的实现。
是 JDK 6 的特性,ServiceLoader。
ServiceLoader启动时会到 resource/META-INF/services/ 目录下读取以 实现类的全限定名 命名的文件。
程序通过 ServiceLoader 动态加载实现类模块,通过扫描 META-INF/services 目录下的配置文件找到实现类的全限定名,把类加载到JVM;
demo:
// 一个接口,两个实现类
public interface Fruit {
void printName();
}
public class Apple implements Fruit {
@Override
public void printName() {
System.out.println("Apple");
}
}
public class Orange implements Fruit {
@Override
public void printName() {
System.out.println("Orange");
}
}
在 src/main/resources/META-INF/services 下新建文件 xxx.xxx.xx.Fruit,这个文件名就是Fruit接口的全限定名,
文件内容:
com.hitol.service.impl.Apple
com.hitol.service.impl.Orange
文件中的内容是 Apple、Orange类的全限定名,可以配置一个也可以配置多个。
public static void main(String[] args) {
ServiceLoader<Fruit> fruits = ServiceLoader.load(Fruit.class);
for (Fruit fruit : fruits) {
fruit.printName();
}
}
会依次调用xxx.xxx.xx.Fruit文件中配置的具体实现类。
应用场景:各种数据库连接
Dubbo SPI
Dubbo SPI 扩展点加载,从 JDK 标准的 SPI 扩展点机制加强而来。
加载的路径约定为: resource/META-INF/dubbo/接口全限定名
增加了对扩展点 IOC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
将上面例子中的xx.Fruit文件移到 resource/META-INF/dubbo/ 目录下,同时需要在 Fruit 类上加 Dubbo 注解 @SPI。
文件内容
orange=com.hitol.util.services.impl.Orange
apple=com.hitol.util.services.impl.Apple
demo:
public static void main(String[] args) {
ExtensionLoader<Fruit> extensionLoader = ExtensionLoader.getExtensionLoader(Fruit.class);
Fruit apple = extensionLoader.getExtension("apple");
Fruit orange = extensionLoader.getExtension("orange");
apple.printName();
orange.printName();
}
Dubbo SPI 的实现封装在 ExtensionLoader 中。
Dubbo 中几乎到处可见 SPI 机制的应用,比如说,
- 反射创建默认实现类,org.apache.dubbo.common.extension.ExtensionLoader#createAdaptiveExtensionClass
- dubbo 协议
Dubbo SPI 的实现
ExtensionLoader.getExtensionLoader
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())
extensionLoader.getExtension
ExtensionLoader.getExtensionLoader
这个方法的逻辑比较简单,是否有 SPI 注解,缓存中没有的话就 new 一个 ExtensionLoader 出来,不过在 new 的时候会去获取 objectFactory 属性的值。第一次 new 的话,会加载 ExtensionFactory,并获取它的默认实现。
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
getAdaptiveExtension()
SPI 修饰的接口的实现类中,获取带有 @Adaptive 注解的实现。
在同一个接口的实现类中,@Adaptive 注解只能修饰其中的一个实现类,表示该接口的默认实现。
getAdaptiveExtension 方法就是获取这个默认的实现类。
SPI(value= "apple") 注解上可以指定 默认的实现类。
extensionLoader.getExtension
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
if ("true".equals(name)) {
return getDefaultExtension();
}
// 获取holder,相当于持有对象的锁
// 从缓存map cachedInstances 中获取,获取不到就new
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
// 双重检测单例模式
// 此处这个锁对象是holder,而不是整个class对象,锁粒度更小,并发更高
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
拓展类对象的获取过程,都是先从缓存中查找,没有在新建对象。最重要的实现逻辑是在 createExtension 方法中。
createExtension
private T createExtension(String name) {
// 先从cachedClasses 缓存map中获取类对象,获取不到则new
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
// 生成具体类实例对象,放入缓存
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// IOC 注入
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
=========================================
private Map<String, Class<?>> getExtensionClasses() {
// 缓存
Map<String, Class<?>> classes = cachedClasses.get();
// 双重检查单例模式
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
// 加载所有的扩展点对象,然后放到缓存中
// SpiExtensionFactory
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
=========================================
private Map<String, Class<?>> loadExtensionClasses() {
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
// internal extension load from ExtensionLoader's ClassLoader first . 先加载 /internal 目录下的扩展点
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName(), true);
// replace("org.apache", "com.alibaba") 替换包名这个骚操作
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"), true);
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
wrapper 类
wrapper 相当于 AOP 动态代理生成的 代理对象。
一个类它是 wrapper 类的条件:
- 实现某个接口
- 类中只有一个属性变量,是该接口的实例
- 只有包含这个属性变量的构造方法。
/**
* test if clazz is a wrapper class
* <p>
* which has Constructor with given class type as its only argument
*/
private boolean isWrapperClass(Class<?> clazz) {
try {
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
Fruit 的 wrapper 类
public class FruitWrapper implements Fruit {
private Fruit fruit;
public FruitWrapper(Fruit fruit) {
this.fruit = fruit;
}
@Override
public void printName() {
System.out.println("this is wrapper");
fruit.printName();
}
}
---
文件内容
orange=com.hitol.util.services.impl.Orange
apple=com.hitol.util.services.impl.Apple
com.hitol.util.services.impl.FruitWrapper
---
ExtensionLoader<Fruit> extensionLoader = ExtensionLoader.getExtensionLoader(Fruit.class);
Fruit apple = extensionLoader.getExtension("apple");
apple.printName();
---
输出内容:
this is wrapper
Apple
输出内容:
this is wrapper
Apple
https://dubbo.apache.org/zh/docs/v2.7/dev/spi/
https://dubbo.apache.org/zh/docs/v2.7/dev/source/dubbo-spi/