Dubbo SPI
基于Java的SPI机制,Dubbo在其思想的基础上自己实现了一套SPI机制,弥补了Java SPI的缺点,并进行了相应的扩展。
1. Dubbo SPI 改进了 Java SPI 的以下问题:
-
Java SPI
是一次性加载、实例化所有的扩展点实现,不支持根据key
值去加载、实例化指定的扩展点实现。 -
Java SPI
不支持IOC、AOP
,Dubbo SPI
则通过自动包装、自动装配等特性实现了IOC、AOP
。 -
ServerLoader
在加载类的过程中如果出现异常无法加载没有相关的异常抛出,导致一旦出现问题需要花时间进行定位。
2. Dubbo SPI 的三个特性
2.1. 自动包装
基于装饰器设计模式,通过创建、配置Wrapper类,从而实现对实现类的增强。我们可以将一些公共的逻辑放置在Wrapper类中,从而实现了公共逻辑与业务逻辑的解耦,同时也更易于扩展和维护。
2.2. 自动装配
类似于Spring的IOC依赖注入的功能,在加载扩展点的实现类时,会遍历所有setter方法,尝试着为其注入其他扩展点依赖。
2.3. 自适应
Dubbo使用URL对象传递配置信息,通过在URL对象中配置对应的key-value键值对,从而实现在调用相应方法时能够通过URL中的配置匹配对应的扩展点实现。
2.4. 自动激活
当我们想通过一个配置激活多个扩展点实现时,可以通过@Activate注解来实现,从而简化了配置。
3. 代码示例:
3.1. 车辆接口
package com.dubbo.service;
import org.apache.dubbo.common.extension.SPI;
@SPI
public interface ICarService {
void speed();
}
3.2. 车辆接口的两个实现类AudiService
、BmwService
package com.dubbo.service.impl;
import com.dubbo.service.ICarService;
public class AudiService implements ICarService {
@Override
public void speed() {
System.out.println("audi drive speed 100KM/H");
}
}
public class BMWService implements ICarService {
@Override
public void speed() {
System.out.println("bmw drive speed 200KM/H");
}
}
3.3. 配置文件
resources\META-INF\services\com.dubbo.service.ICarService
audi=com.dubbo.service.impl.AudiService
bmw=com.dubbo.service.impl.BMWService
3.4. 测试方法
private static void dubboSpi() {
ExtensionLoader<ICarService> extensionLoader = ExtensionLoader.getExtensionLoader(ICarService.class);
ICarService carService = extensionLoader.getExtension("audi");
carService.speed();
}
// 输出
audi drive speed 100KM/H
4. 源码解析
4.1 获取扩展点加载器
Main方法
ExtensionLoader.getExtensionLoader(ICarService.class);
ICarService carService = extensionLoader.getExtension("audi");
org.apache.dubbo.common.extension.ExtensionLoader
// key:扩展点接口-扩展点加载器
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
// 获取扩展点加载器
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
...
// 尝试从缓存中获取扩展点加载器
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;
}
获取到扩展点加载器后,调用扩展点加载器的getExtension
方法获取扩展点实现对象
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
// 如果传入name为true,则获取默认扩展实现
if ("true".equals(name)) {
return getDefaultExtension();
}
// 获取实现类实例持有器,如果没有则创建一个
final Holder<Object> holder = getOrCreateHolder(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;
}
先从缓存中获取扩展点实现实例,如果没有获取到则调用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));
}
}
// 如果是Lifecycle的实现类,则调用initialize()方法
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
下面是getExtensionClasses()
源码解析,加载指定路径下实现点文件中的别名与实现类
Java SPI
会扫描META-INF/services/
目录下的文件从而检测扩展点实现类,Dubbo SPI
该步骤是在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;
}
加载META-INF/dubbo/internal/
、META-INF/dubbo/
、META-INF/services/
目录下该扩展点文件中的别名与对应的实现类,放入到缓存Map中,并返回
private Map<String, Class<?>> loadExtensionClasses() {
// 缓存当前扩展点的默认实现
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
// 加载 META-INF/dubbo/internal/ 目录下当前扩展点对应的具体实现类列表 (下面会详说)
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName(), true);
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"), true);
// 加载 META-INF/dubbo/ 目录下当前扩展点对应的具体实现类列表
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
// 加载 META-INF/services/ 目录下当前扩展点对应的具体实现类列表
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
// 返回别名-扩展点实现类Map,这里如果别名一致会覆盖,后来的会覆盖前面的
return extensionClasses;
}
loadDirectory()
方法中,会通过类加载器加载扩展点文件,并解析其中的内容,存入extensionClasses Map缓存中
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst) {
// 获取文件全路径名
String fileName = dir + type;
try {
Enumeration<java.net.URL> urls = null;
// 获取加载ExtensionLoader类的类加载器
ClassLoader classLoader = findClassLoader();
// 如果是第一次加载,则获取类加载器
if (extensionLoaderClassLoaderFirst) {
// 获取加载ExtensionLoader类的类加载器
ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
// 如果当前系统的类加载器不是加载ExtensionLoader类的类加载器时,则通过加载ExtensionLoader类的类加载器获取文件对应的url访问路径列表
if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
urls = extensionLoaderClassLoader.getResources(fileName);
}
}
// 如果urls为空
if(urls == null || !urls.hasMoreElements()) {
if (classLoader != null) {
// 加载文件对应的url访问路径列表
urls = classLoader.getResources(fileName);
} else {
// 使用系统类加载器、根类加载器加载文件对应的url访问路径列表
urls = ClassLoader.getSystemResources(fileName);
}
}
if (urls != null) {
// 遍历url访问路径列表
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
// 加载文件内容(下面会详说)
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
解析实现点文件,获取别名与对应的实现类全名,加载实现类,放入到extensionClasses
缓存Map中
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 {
// 假设 audi=com.lbb.service.impl.AudiService =》则name=audi, line=com.lbb.service.impl.AudiService
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) {
// 解析别名、加载实现类,并放入到extensionClasses缓存Map中(下面详说)
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);
}
}
查看是否存在@Adaptive注解、是否是包装类,如果都不是则解析别名与实现类,放入缓存Map中
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
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.");
}
if (clazz.isAnnotationPresent(Adaptive.class)) {
// 如果存在@Adaptive注解,则缓存到cachedAdaptiveClass中
cacheAdaptiveClass(clazz);
} else if (isWrapperClass(clazz)) {
// 如果这个类的构造方法的参数类型是实现点接口,则说明是包装类,缓存到cachedWrapperClasses List中
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);
}
}
// 解析别名,处理分隔符
String[] names = NAME_SEPARATOR.split(name);
if (ArrayUtils.isNotEmpty(names)) {
// 缓存实现类-别名
cacheActivateClass(clazz, names[0]);
for (String n : names) {
// 缓存实现类与别名
cacheName(clazz, n);
// 缓存别名与实现类到extensionClasses 缓存Map中
saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
下面是injectExtension()的源码解析,通过获取set方法参数与名称,获取对应注入类实例,反射注入依赖对象
private T injectExtension(T instance) {
if (objectFactory == null) {
return instance;
}
try {
// 遍历实现类中的所有方法
for (Method method : instance.getClass().getMethods()) {
// 如果不是set方法,则继续遍历
if (!isSetter(method)) {
continue;
}
// 如果方法上存在@DisableInject注解,则继续遍历
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
// 获取set方法的第一个参数的类型
Class<?> pt = method.getParameterTypes()[0];
// 如果该参数类型是基础数据类型,则继续遍历
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
// 解析set后的名称,setCarService =》 carService
String property = getSetterProperty(method);
// 根据解析后的名称去工厂中获取对应的扩展类对象
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
// 通过反射调用set方法进行注入
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;
}
下面是initExtension()
方法的源码,调用实现类对象的初始化方法进行初始化
private void initExtension(T instance) {
// 检测是否实现了Lifecycle接口
if (instance instanceof Lifecycle) {
Lifecycle lifecycle = (Lifecycle) instance;
// 如果实现了,则调用其初始化方法
lifecycle.initialize();
}
}