乐于分享
好东西不私藏

Dubbo SPI源码深度解析:从配置到实例的完整流程

Dubbo SPI源码深度解析:从配置到实例的完整流程

用Dubbo时,你肯定遇到过这样的困惑:明明引入了扩展依赖,为什么框架能自动找到实现类?今天我们扒开SPI的源码,从配置加载到实例创建,一步步讲清楚Dubbo扩展机制的底层逻辑。

Dubbo SPI的核心入口:ExtensionLoader

Dubbo的SPI扩展机制由ExtensionLoader类主导,所有扩展的加载、实例化都围绕这个类展开。我们从最常用的getExtension(String name)方法开始分析:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
public<T> T getExtension(String name){if(name ==null|| name.isEmpty()){thrownewIllegalArgumentException("Extension name == null");}// 1. 检查缓存中的实例Holder<Object> holder = cachedInstances.get(name);if(holder ==null){ cachedInstances.putIfAbsent(name,newHolder<>()); holder = cachedInstances.get(name);}Object instance = holder.get();if(instance ==null){synchronized(holder){ instance = holder.get();if(instance ==null){// 2. 创建扩展实例 instance = createExtension(name); holder.set(instance);}}}return(T) instance;}

关键标注:①cachedInstances是实例缓存,避免重复创建;②createExtension是实例创建的核心方法。

配置加载:从META-INF到实现类列表

createExtension方法首先要解决的问题是:如何找到扩展的实现类?答案就在loadExtensionClasses方法里——它会加载META-INF/dubbo/META-INF/dubbo/internal/META-INF/services/下的配置文件。

简化后的核心代码:

  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
privateMap<String,Class<?>> loadExtensionClasses(){// 加载配置文件 loadDirectory(configurations, DUBBO_DIRECTORY);// META-INF/dubbo/ loadDirectory(configurations, DUBBO_INTERNAL_DIRECTORY);// META-INF/dubbo/internal/ loadDirectory(configurations, SERVICES_DIRECTORY);// META-INF/services/return configurations;}privatevoid loadDirectory(Map<String,Class<?>> extensions,String dir){String fileName = dir + type.getName();try{// 读取配置文件内容Enumeration<URL> urls = classLoader.getResources(fileName);while(urls.hasMoreElements()){ URL url = urls.nextElement();// 解析配置文件,将键值对(名称→实现类)存入extensions loadResource(extensions, url);}}catch(IOException e){ logger.error("...", e);}}

关键逻辑:通过类加载器读取指定目录下的配置文件,将扩展名称与实现类的映射关系存入extensions集合。

实例创建与依赖注入

找到实现类后,createExtension会通过反射创建实例,并自动注入依赖(Dubbo称为“自动包装”):

  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
private T createExtension(String name){// 1. 获取实现类Class<?> clazz = getExtensionClasses().get(name);if(clazz ==null){thrownewIllegalArgumentException("...");}try{// 2. 反射创建实例 T instance =(T) clazz.newInstance();// 3. 注入依赖(比如@Adaptive注解的扩展) injectExtension(instance);// 4. 包装扩展(比如AOP代理)return wrapInstance(instance);}catch(Exception e){thrownewIllegalStateException("...");}}

重点injectExtension方法会遍历实例的setter方法,自动注入其他扩展(比如setProtocol(Protocol protocol)会自动注入Protocol的实现)。

用UML理清核心流程

为了更直观展示SPI的完整流程,我们绘制了UML流程图:

结尾

总结一下,Dubbo SPI的核心就是ExtensionLoader通过加载配置文件、反射创建实例、注入依赖,实现了扩展的“即插即用”。其实没那么复杂对吧?你平时用SPI时遇到过什么坑?比如配置文件放错目录?或者依赖注入失败?评论区聊聊,咱们一起避坑~

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » Dubbo SPI源码深度解析:从配置到实例的完整流程

猜你喜欢

  • 暂无文章