Dubbo SPI机制
SPI是什么?
- SPI出现的背景:在 Java 开发中,经常会依赖第三方库(jar 包)。这些库里可能定义了一些 标准接口(比如数据库驱动、日志接口、序列化接口),并在内部调用了接口的方法。但是我们想在自己的业务中扩展这个接口(写新的实现类),又不能直接修改第三方库的源码,需要一种
解耦
的机制,让第三方库可以“发现”并调用我们的实现类。 - SPI解决方案:通过一种约定的目录(如
META-INF/services/
接口全限定名),在文件中声明接口与实现类的映射关系,第三方框架ServiceLoader
通过获取文件内容,动态加载实现类,在运行时接入我们的扩展类。
JDK SPI
JDK SPI缺点
:
- jdk 自带SPI机制,实例化是用的反射无参构造方法,
不支持构造器注入
- jdk 自带SPI机制,
不支持依赖注入
- jdk 自带SPI机制,会将全部实现类加载,
不支持指定实现类加载
Demo:
public interface TestService {String test();
}
public class TestServiceImpl implements TestService {@Overridepublic String test() {return "我是TestServiceImpl";}
}
ServiceLoader<TestService> testServices = ServiceLoader.load(TestService.class);
Iterator<TestService> iterator = testServices.iterator();
while(iterator.hasNext()) {System.out.println(iterator.next().test());
}
配置文件如下:
输出如下:
Dubbo SPI
Dubbo 扩展能力
:
- 支持依赖注入(
IOC
) - 支持获取指定实现类
- 支持wrap自动装配(
理解为装饰器模式、AOP
) - 支持自动激活(获取批量实现类)
- 支持自定义自适应类、动态生成自适应类(根据参数获取具体实现类,通常方法参数需要包含URL或者参数包含getUrl方法)
常用api
:
- ExtensionLoader.getExtension(“key”):获取xxx接口文件key为key的实现类
- ExtensionLoader.getAdaptiveExtension():获取xxx接口的自适应扩展类
- ExtensionLoader.getActivateExtensions():获取xxx接口的自动装配类(标注了@Activate的实现类)
Demo:
@SPI("openAi")
public interface AiService {@Adaptivevoid requestAi();
}
public class OpenAiServiceImpl implements AiService {@Overridepublic void requestAi() {System.out.println("我是OpenAiServiceImpl");}
}
ExtensionLoader<AiService> extensionLoader = ScopeModelUtil.getModuleModel(null).getExtensionLoader(AiService.class);AiService openAi = extensionLoader.getExtension("openAi");openAi.requestAi();
配置文件:
输出:
Dubbo SPI 原理与图解
流程图
ExtensionLoader.getExtension(“key”) 流程图
ExtensionLoader.getAdaptiveExtension() 流程图
ExtensionLoader.getActivateExtensions()流程图
源码解析
扫描文件:
private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {...// 缓存默认自适应类,@SPI注解的value字段cacheDefaultExtensionName();Map<String, Class<?>> extensionClasses = new HashMap<>();// META-INF/dubbo/internal/;META-INF/dubbo/;META-INF/services/;扫描三个路径 用jdk spi机制实现 .for (LoadingStrategy strategy : strategies) {loadDirectory(extensionClasses, strategy, type.getName());...}return extensionClasses;
}private void loadDirectoryInternal(Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type)throws InterruptedException {// 指定目录 + 类全命名String fileName = loadingStrategy.directory() + type;try {List<ClassLoader> classLoadersToLoad = new LinkedList<>();...// 加载文件Map<ClassLoader, Set<java.net.URL>> resources =ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad);resources.forEach(((classLoader, urls) -> {loadFromClass(extensionClasses,loadingStrategy.overridden(),urls,classLoader,loadingStrategy.includedPackages(),loadingStrategy.excludedPackages(),loadingStrategy.onlyExtensionClassLoaderPackages());}));}...}
文件每行全命名类归纳(@adaptive、wrap、@Activate):
private void loadResource(Map<String, Class<?>> extensionClasses,ClassLoader classLoader,java.net.URL resourceURL,boolean overridden,String[] includedPackages,String[] excludedPackages,String[] onlyExtensionClassLoaderPackages) {try {List<String> newContentList = getResourceContent(resourceURL);String clazz;for (String line : newContentList) {try {// 解析格式为key=valueString name = null;int i = line.indexOf('=');if (i > 0) {name = line.substring(0, i).trim();clazz = line.substring(i + 1).trim();} else {clazz = line;}if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)&& isIncluded(clazz, includedPackages)&& !isExcludedByClassLoader(clazz, classLoader, onlyExtensionClassLoaderPackages)) {// 加载具体类信息loadClass(classLoader, extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);}} ...}}}private void loadClass(ClassLoader classLoader,Map<String, Class<?>> extensionClasses,java.net.URL resourceURL,Class<?> clazz,String name,boolean overridden) {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.");}boolean isActive = loadClassIfActive(classLoader, clazz);if (!isActive) {return;}// 带有@Adaptive的类 缓存spi自适应扩展类if (clazz.isAnnotationPresent(Adaptive.class)) {cacheAdaptiveClass(clazz, overridden);} else if (isWrapperClass(clazz)) {// 缓存wrap自动装配类 后续aop铺垫cacheWrapperClass(clazz);} else {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)) {// 带有@activate注解 的类 缓存自动装配类cacheActivateClass(clazz, names[0]);for (String n : names) {cacheName(clazz, n);saveInExtensionClass(extensionClasses, clazz, n, overridden);}}}}
依赖注入 与 wrap自动装配:
private T createExtension(String name, boolean wrap) {// 获取key=name的类Class<?> clazz = getExtensionClasses().get(name);if (clazz == null || unacceptableExceptions.contains(name)) {throw findException(name);}try {T instance = (T) extensionInstances.get(clazz);if (instance == null) {// 创建实例extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));instance = (T) extensionInstances.get(clazz);instance = postProcessBeforeInitialization(instance, name);// set方法 依赖注入injectExtension(instance);instance = postProcessAfterInitialization(instance, name);}if (wrap) {List<Class<?>> wrapperClassesList = new ArrayList<>();if (cachedWrapperClasses != null) {wrapperClassesList.addAll(cachedWrapperClasses);// 排序 @Wrapper order 进行排序wrapperClassesList.sort(WrapperComparator.COMPARATOR);Collections.reverse(wrapperClassesList);}if (CollectionUtils.isNotEmpty(wrapperClassesList)) {for (Class<?> wrapperClass : wrapperClassesList) {Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);// 根据wrapper注解 条件属性 进行过滤boolean match = (wrapper == null)|| ((ArrayUtils.isEmpty(wrapper.matches())|| ArrayUtils.contains(wrapper.matches(), name))&& !ArrayUtils.contains(wrapper.mismatches(), name));if (match) {// 装饰器模式 层层嵌套 Aop instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));instance = postProcessAfterInitialization(instance, name);}}}}initExtension(instance);return instance;} catch (Throwable t) {throw new IllegalStateException("Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: "+ t.getMessage(),t);}}
如果对你有帮助,辛苦点个赞,谢谢啦,朋友!!!