dubbo spi
SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展
Dubbo 并未使用 Java SPI,而是重新实现了一套功能更强的 SPI 机制。Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中,通过 ExtensionLoader,我们可以加载指定的实现类。Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径下,配置内容如下。
optimusPrime = org.apache.spi.OptimusPrime
bumblebee = org.apache.spi.Bumblebee
与 Java SPI 实现类配置不同,Dubbo SPI 是通过键值对的方式进行配置,这样我们可以按需加载指定的实现类。另外,在测试 Dubbo SPI 时,需要在 Robot 接口上标注 @SPI 注解
service
@SPI(value = "impl")
public interface PrintService {
public void printInfo();
}
public class PrintServiceImpl implements PrintService {
@Override
public void printInfo() {
System.out.println("hello printInfo "+LocalDateTime.now());
}
}
public class PrintServiceSecondImpl implements PrintService {
@Override
public void printInfo() {
System.out.println("PrintServiceSecondImpl "+LocalDateTime.now());
}
}
META-INF/dubbo目录下
文件
com.ghgcn.dubbo.provider.service.PrintService
impl=com.ghgcn.dubbo.provider.service.impl.PrintServiceImpl
qq=com.ghgcn.dubbo.provider.service.impl.PrintServiceSecondImpl
* 加载
public class PrintServiceApplication {
public static void main(String[] args) {
//1.加载扩展加载器
ExtensionLoader<PrintService> extensionLoader = ExtensionLoader.getExtensionLoader(PrintService.class);
//获取指定的实现类
PrintService implPrintService = extensionLoader.getExtension("impl");
//调用
implPrintService.printInfo();
//获取指定的实现类
PrintService qqPrintService = extensionLoader.getExtension("qq");
//调用
qqPrintService.printInfo();
}
}
- 加载getExtensionLoader
@SuppressWarnings("unchecked")
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 an interface!");
}
//没有注解SPI
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
//ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(); 从map中获取
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
//为空
if (loader == null) {
//就new 一个再次放进Map中
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
//再次获取出来
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
//返回
return loader;
}
- getExtension方法 extensionLoader.getExtension(“impl”);
/**
从配置的扩展类name到获得该类的实例化的过程
*/
public T getExtension(String name) {
//这里是上面的impl 不能为空
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
//如果是true就获取默认的SPI扩展实现
if ("true".equals(name)) {
//1. 获取默认SPI扩展
return getDefaultExtension();
}
//创建Holder 2.
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
//双重较验
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//3. 根据名称创建SPI实现
instance = createExtension(name);
//设置值
holder.set(instance);
}
}
}
//返回实例
return (T) instance;
}
-
getDefaultExtension加载默认实现
-
getOrCreateHolder
private Holder<Object> getOrCreateHolder(String name) {
//从缓存中获取
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
// private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>(); 一个map key是传进来的name,value是 holder
//如果为空就new一个出来并放入缓存
cachedInstances.putIfAbsent(name, new Holder<>());
holder = cachedInstances.get(name);
}
return holder;
}
holder
public class Holder<T> {
private volatile T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
- createExtension
private T createExtension(String name) {
//根据接口名获取所有实现类
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);
}
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
- getExtensionClasses 获取所有扩展
private Map<String, Class<?>> getExtensionClasses() {
//从缓存中拿map, 如果没有,就调用loadExtensionClasses
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//加载扩展类
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
- loadExtensionClasses
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
//调用cacheDefaultExtensionName拿到默认实现类
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
//调用loadDirectory从几个文件下寻找扩展类配置文件
//DUBBO_INTERNAL_DIRECTORY
//DUBBO_DIRECTORY
//SERVICES_DIRECTORY
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
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;
}
- cacheDefaultExtensionName
变量路径
private static final String SERVICES_DIRECTORY = "META-INF/services/";
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
private void cacheDefaultExtensionName() {
//获取类型上的SPI注解
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
//不为空
if (defaultAnnotation != null) {
//获取SPI上的注解, 如果有设置value值,则取出, 这个值是默认实现类噢
String value = defaultAnnotation.value();
if ((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 impl SPI中的值
cachedDefaultName = names[0];
}
}
}
}
就是将SPI注解的value取出来来对应默认的实现类
- loadDirectory 方法
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
String fileName = dir + type;
try {
Enumeration<java.net.URL> urls;
//获取 classLoader 阿里封装的获取 classLoader 的方法
ClassLoader classLoader = findClassLoader();
//判断是否为空
if (classLoader != null) {
// jdk的方法, 与java spi一样的噢
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
//用url获取到文件流
if (urls != null) {
while (urls.hasMoreElements()) {
//解析每一行, 将=号前面的赋值为name,后面的赋值为实现类的全限定路径
java.net.URL resourceURL = urls.nextElement();
//反射实例化每一行的实现类, 并调用loadClass方法实现对extensionClasses的最终赋值(它new了一个extensionClasses的map对象直到后面才进行赋值
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
- findClassLoader获取classLoader
private static ClassLoader findClassLoader() {
return ClassUtils.getClassLoader(ExtensionLoader.class);
}
- loadResource
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
String line;
//读取文件中的每一行
while ((line = reader.readLine()) != null) {
//判断是不是注释开头的
final int ci = line.indexOf('#');
if (ci >= 0) {
line = line.substring(0, ci);
}
line = line.trim();
//这一行有数据
if (line.length() > 0) {
try {
String name = null;
//判断 是否为=号
int i = line.indexOf('=');
//如果有
if (i > 0) {
//分割名称
name = line.substring(0, i).trim();
//分割=号后面的实现类
line = line.substring(i + 1).trim();
}
//如果有实现类就加载见下面
if (line.length() > 0) {
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
}
} catch (Throwable t) {
IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
- loadClass
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
//判断当type是不是当前的接口或者父类,不是就抛出异常
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + " is not subtype of interface.");
}
//如果是Adaptive注解的类, 就把它放到cacheAdaptiveClass缓存中
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz);
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
} else {
//获取构造方法
clazz.getConstructor();
//判断名称
if (StringUtils.isEmpty(name)) {
name = findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
//分割name, 因为配置文件中name可以有很多个,然后每个name对应赋值一个实现类对象(即使对象都相同)
String[] names = NAME_SEPARATOR.split(name);
if (ArrayUtils.isNotEmpty(names)) {
//放入缓存
cacheActivateClass(clazz, names[0]);
for (String n : names) {
//缓存实现类的全类名,名称
cacheName(clazz, n);
//保存扩展
saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
判断是否是Adaptive等注解的类, 就把它放到对应的cacheAdaptiveClass等缓存中
//添加Adaptive注解类的缓存
private void cacheAdaptiveClass(Class<?> clazz) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: "
+ cachedAdaptiveClass.getClass().getName()
+ ", " + clazz.getClass().getName());
}
}
cacheWrapperClass 添加缓存
private void cacheWrapperClass(Class<?> clazz) {
if (cachedWrapperClasses == null) {
cachedWrapperClasses = new ConcurrentHashSet<>();
}
cachedWrapperClasses.add(clazz);
}
分割name, 因为配置文件中name可以有很多个,然后每个name对应赋值一个实现类对象(即使对象都相同)
cacheActivateClass
private void cacheActivateClass(Class<?> clazz, String name) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(name, activate);
} else {
// support com.alibaba.dubbo.common.extension.Activate
com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
if (oldActivate != null) {
cachedActivates.put(name, oldActivate);
}
}
}
cacheName
private void cacheName(Class<?> clazz, String name) {
if (!cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, name);
}
}
saveInExtensionClass
private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
Class<?> c = extensionClasses.get(name);
if (c == null) {
//如果为null就放入缓存
extensionClasses.put(name, clazz);
} else if (c != clazz) {
throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName());
}
}
到这个扩展类就加载完成
返回下面这个方法createExtension
private T createExtension(String name) {
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);
}
//实现依赖注入
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
- injectExtension 依赖注入
private T injectExtension(T instance) {
try {
//如果objectFactory不可能为空,见下面,构造方法里已经初始化过了
if (objectFactory != null) {
//遍历实例所有的方法
for (Method method : instance.getClass().getMethods()) {
//判断是否是set方法 如果是setter方法
if (isSetter(method)) {
/**
* Check {@link DisableInject} to see if we need auto injection for this property
*/
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
Class<?> pt = method.getParameterTypes()[0];
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
//取setter方法属性
String property = getSetterProperty(method);
//根据第一个参数和类型 从List<ExtensionFactory>中获取实例
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
//利用反射将获取的依赖注入到当前实例中
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("Failed to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
在上面代码中,objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory。前者用于创建自适应的拓展,后者是用于从 Spring 的 IOC 容器中获取所需的拓展
Dubbo IOC 目前仅支持 setter 方式注入
- private final ExtensionFactory objectFactory;`
因为再调用ExtensionLoader.getExtensionLoader(Color.class);
方法的时候, dubbo已经对扩展类IOC进行初始化了
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
- ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
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("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
- createAdaptiveExtension
@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
try {
//class org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory这个类的实现
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
- getAdaptiveExtensionClass
private Class<?> getAdaptiveExtensionClass() {
//又是加载所有的扩展类
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
- getExtensionClasses和上面的流程一样
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() {
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
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;
}