本篇文章为你整理了Dubbo 源码解析(一)Dubbo SPI(深度剖析dubbo源码)的详细内容,包含有dubbo源码解析20pdf 深度剖析dubbo源码 dubbo示例代码 dubbo开源时间 Dubbo 源码解析(一)Dubbo SPI,希望能帮助你了解 Dubbo 源码解析(一)Dubbo SPI。
Dubbo 扩展机制 SPI
在 Dubbo 中,SPI 贯穿在整个 Dubbo 的核心。所以有必要先对 Dubbo 中 SPI 做一个详细的介绍。
JDK SPI
之前写过一篇介绍 JDK SPI 的博客,可以点击查看。
Dubbo SPI
Dubbo 实现了自己的 SPI 机制
除了可以配置在 META-INF/services 目录下,还可以配置在 META-INF/dubbo 和 META-INF/dubbo/internal
配置文件内容采用 key=value 的形式。这样可以按需实例化加载类,而不用像 JDK 一样在启动时一次性加载实例化扩展点的所有实现,浪费性能。
出现异常时可以更准确定位
增加了对 Duboo 自己实现的 IOC 和 AOP 的支持
这里使用的版本是 dubbo-2.6.4
这里的分析流程是根据例子来分析内部源码的实现
注意,在阅读下面的源码解析时,有些跟当前流程无关的代码我会标注 忽略点 - X,表示这段代码先跳过,不影响当前流程,且在后面用到的地方我会再重新解释该忽略点的意思。
1、Dubbo SPI 的基本示例
接口,注意加 @SPI 注解
@SPI
public interface Robot {
void sayHello();
实现类
public class MIRobot implements Robot {
@Override
public void sayHello() {
System.out.println("大家好,我是小米机器人...");
在文件夹 resources/META-INF/services 下添加配置文件,文件名 com.lin.spi.Robot(接口的路径)
文件内容
miRobot = com.lin.spi.MIRobot
在测试类中调用
public class DubboSPITest {
@Test
public void test() {
ExtensionLoader Robot extensionLoader =
ExtensionLoader.getExtensionLoader(Robot.class);
Robot miRobot = extensionLoader.getExtension("miRobot");
miRobot.sayHello();
输出
大家好,我是小米机器人...
Process finished with exit code 0
上面就是 Dubbo SPI 的基本使用,接下来开始源码分析。
(1)入口方法 ExtensionLoader#getExtensionLoader(Class T type)
@SuppressWarnings("unchecked")
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;
getExtensionLoader(Class T type) 的作用只是简单的根据 type 包装一个 ExtensionLoader 实例,缓存在 EXTENSION_LOADERS 中,然后返回 ExtensionLoader 实例。
其中 ExtensionLoader 实例化时 objectFactory 的创建我们这里先忽略
(2)调用方法 ExtensionLoader#getExtension(String name) 获取具体的实例
@SuppressWarnings("unchecked")
public T getExtension(String name) {
// ...
Holder Object holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder Object
holder = cachedInstances.get(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;
getExtension(String name) 的作用就是创建我们在配置文件配置的扩展点实现类(例子中的 MIRobot 实例),包装在 Holder 中然后缓存进 cachedInstances,返回实例。
创建扩展类
@SuppressWarnings("unchecked")
private T createExtension(String name) {
// 根据 type 去配置文件中加载配置的所有扩展类存进 Map String, Class ? 缓存,再根据 name 得到特定的 clazz
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 (wrapperClasses != null !wrapperClasses.isEmpty()) {
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 + ") could not be instantiated: " + t.getMessage(), t);
createExtension(String name) 方法的逻辑包含如下步骤
获取所有的扩展类(实例中是返回 miRobot - "class com.lin.spi.MIRobot" )
通过反射创建拓展对象
向拓展对象中注入依赖(这里暂时忽略)
将拓展对象包裹在相应的 Wrapper 对象中(这里暂时忽略)
(2.1)获取所有的扩展类
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() {
// 获取 @SPI 注解
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length 1) {
// 检测 @SPI 注解内容是否合法
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
if (names.length == 1) cachedDefaultName = names[0];
Map String, Class ? extensionClasses = new HashMap String, Class ? ();
// 加载指定文件夹下的配置文件
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); // META-INF/dubbo/internal
loadDirectory(extensionClasses, DUBBO_DIRECTORY); // META-INF/dubbo
loadDirectory(extensionClasses, SERVICES_DIRECTORY); // META-INF/services
return extensionClasses;
loadDirectory 方法先通过 classLoader 获取所有资源链接(配置文件链接),然后再通过 loadResource 方法读取和解析配置文件,把解析出的每一个 clazz 调用 loadClass() 在 cachedNames、extensionClasses、cachedActivates 等缓存起来
2、Dubbo AOP 实现
例子
在上面的例子基础上,新建类 RobotWrapper
public class RobotWrapper implements Robot {
private Robot robot;
public RobotWrapper(Robot robot) {
this.robot = robot;
@Override
public void sayHello() {
System.out.println("before...");
this.robot.sayHello();
System.out.println("after...");
在配置文件中写上
miRobot = com.lin.spi.MIRobot
wrapper = com.lin.spi.RobotWrapper
关于 RobotWrapper,一定要有构造函数才会生效,同时在配置文件中可以不用写 wrapper=,也可以同时存在多个 xxxWrapper 实现
接下来不用改动原来的代码,直接运行,
输出:
before...
大家好,我是小米机器人...
after...
getExtensionClass(key) - getExtensionClasses() - loadExtensionClasses() - loadDirectory() - loadResource() - loadClass()
private void loadClass(Map String, Class ? extensionClasses, java.net.URL resourceURL, Class ? clazz, String name) throws NoSuchMethodException {
// ...
if () {
} else if (isWrapperClass(clazz)) { // 判断 clazz 是否有构造函数 忽略点-3的解释
Set Class ? wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet Class ? ();
wrappers = cachedWrapperClasses;
wrappers.add(clazz); // 把 clazz 存进缓存中
} else {
private boolean isWrapperClass(Class ? clazz) {
try {
clazz.getConstructor(type); // clazz 是否有 type 作为参数的构造函数
return true;
} catch (NoSuchMethodException e) {
return false;
接下来在 clazz 实例化时,
@SuppressWarnings("unchecked")
private T createExtension(String name) {
// ...
Set Class ? wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null !wrapperClasses.isEmpty()) {
// 取出所有的 wrapperClass,遍历,取出每一个,把 instance 传进 wrapperClass 的构造函数并实例化,赋值给 instance
// 最后返回的 instance 就是被 wrapper 层层包裹的结果
// 代入例子中,instance = RobotWrapper.class.getConstructor(Robot.class).newInstance(miRobot)
// 类似 instance = new RobotWrapper(miRobot)
for (Class ? wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
// ...
3、Dubbo IOC 实现
官网解释
Dubbo IOC 是通过 setter 方法注入依赖。Dubbo 首先会通过反射获取到实例的所有方法,然后再遍历方法列表,检测方法名是否具有 setter 方法特征。若有,则通过 ObjectFactory 获取依赖对象,最后通过反射调用 setter 方法将依赖设置到目标对象中。
Dubbo IOC 这部分可以结合 Dubbo 的自适应扩展来讲
4、什么是自适应扩展?
前面我们讲解 Dubbo 可以通过 ExtensionLoader.getExtensionLoader(XXXClass).getExtension(key) 的形式来获取某个接口的实现类,但这种形式属于硬编码来指定引用哪个实现。而现在某些扩展希望可以在被调用时,根据运行时参数进行加载,这需要自适应扩展来实现。
首先先来看和自适应扩展相关的两个参数,一个是注解 @Adaptive,一个是 com.alibaba.dubbo.common.URL
@Adaptive 可修饰在类和方法上,
当修饰在类上时,表示该类为所实现的接口的代理类实现
当修饰在方法上时,Dubbo 会自动生成适配器类,会从 URL 中取值作为扩展点名去加载实现类并实例化,最后再使用这个实例调用对应的方法。
例子:
@SPI
public interface Robot {
@Adaptive("robot")
void sayHello(URL url);
public class AdaptiveRobot implements Robot {
private Robot robot;
public void setRobot(Robot robot) {
this.robot = robot;
@Override
public void sayHello(URL url) {
System.out.println("在代理类内部通过 URL 和 SPI 机制获取和加载具体的 Robot 实现类,并调用目标方法");
this.robot.sayHello(url);
public class MIRobot implements Robot {
@Override
public void sayHello(URL url) {
System.out.println("hello");
import com.alibaba.dubbo.common.URL;
public class DubboSPITest {
@Test
public void test() {
ExtensionLoader Robot extensionLoader =
ExtensionLoader.getExtensionLoader(Robot.class);
Map String, String map = new HashMap ();
map.put("robot", "miRobot"); // key=robot 由注解 @Adaptive("robot") 决定
URL url = new URL("", "", 1, map);
Robot adaptiveRobot = extensionLoader.getExtension("adaptiveRobot");
adaptiveRobot.sayHello(url);
输出:
在代理类内部通过 URL 和 SPI 机制获取和加载具体的 Robot 实现类,并调用目标方法
hello
在执行 Class ? clazz = getExtensionClasses().get("adaptiveRobot"); 并实例化 instance 后,调用 injectExtension(instance) 方法向扩展实例中注入依赖
@SuppressWarnings("unchecked")
private T createExtension(String name) {
Class ? clazz = getExtensionClasses().get(name);
// ...
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
// ...
injectExtension(instance);
// ...
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
接下来看 injectExtension(instance) 的具体实现
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
// 检测方法是否以 set 开头,且方法仅有一个参数,且方法访问级别为 public
if (method.getName().startsWith("set")
method.getParameterTypes().length == 1
Modifier.isPublic(method.getModifiers())) {
// 获取 setter 方法参数类型
Class ? pt = method.getParameterTypes()[0];
try {
// 获取属性名,比如 setRobot 方法对应属性名 robot
String property = method.getName().length() 3 ?
method.getName().substring(3, 4).toLowerCase() +
method.getName().substring(4) : "";
// 从 ObjectFactory 中获取依赖对象 eg. XXX$Adaptive
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
// 通过反射调用 setter 方法设置依赖
method.invoke(instance, object); // 往示例中的 AdaptiveRobot 实例的 setRobot() 方法中注入 Robot$Adaptive 自适应类
} catch (Exception e) {
logger.error("fail to inject via method...");
} catch (Exception e) {
logger.error(e.getMessage(), e);
return instance;
这部分源码解释看注释就可以,流程很清晰,主要说下里面的 Object object = objectFactory.getExtension(pt, property); 的 objectFactory。
objectFactory 的实例化
每一个 objectFactory 的创建都是在 ExtensionLoader 实例化的时候,
private ExtensionLoader(Class ? type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
接下来看 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("fail to create adaptive instance: ...");
} else {
throw new IllegalStateException("fail to create adaptive instance: ...");
return (T) instance;
private T createAdaptiveExtension() {
try {
// 获取自适应拓展类,并通过反射实例化,调用 injectExtension 方法向拓展实例中注入依赖
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension ...");
private Class ? getAdaptiveExtensionClass() {
// 通过 SPI 获取所有的拓展类,例子中指所有 Robot 接口实现类
getExtensionClasses();
// 如果某个实现类被 Adaptive 注解修饰了,那么该类就会被赋值给 cachedAdaptiveClass 变量。
// 那么这里直接返回,不创建自适应扩展类
// 这也就是为什么说被 @Adaptive 注解修饰在类上和方法上不一样
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
// 创建自适应拓展类
return cachedAdaptiveClass = createAdaptiveExtensionClass();
现在,世界线收束,我们再从 getExtensionClasses(ExtensionFactory.class); 方法看起,一层层进到最里面的 loadClass() 方法时,这个接口 ExtensionFactory.class 的实现类有 AdaptiveExtensionFactory、SpiExtensionFactory 和 SpringExtensionFactory。其中 AdaptiveExtensionFactory 类上被注解 @Adaptive 修饰,表示该类是该接口的适配器,不提供具体业务支持,会根据在运行时的一些状态来选择具体调用 ExtensionFactory 的哪个实现。
private void loadClass(Map String, Class ? extensionClasses, java.net.URL resourceURL, Class ? clazz, String name) throws NoSuchMethodException {
// ...
if (clazz.isAnnotationPresent(Adaptive.class)) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
// ...
返回 cachedAdaptiveClass = adaptiveExtensionFactory
因此,当一开始 ExtensionLoader.getExtensionLoader(Robot.class) 初始化后,得到(忽略点 - 1 的解释)
private ExtensionLoader(Robot.class) {
this.type = Robot.class;
objectFactory = adaptiveExtensionFactory;
搞清楚 objectFactory 等于什么之后,我们继续看 injectExtension(instance) 的内容,
private T injectExtension(T instance) {
// ...
// 从 ObjectFactory 中获取依赖对象
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
// 通过反射调用 setter 方法设置依赖
method.invoke(instance, object);
// ...
return instance;
objectFactory.getExtension(pt, property) 也就是 adaptiveExtensionFactory.getExtension(pt, property),而 AdaptiveExtensionFactory 在实例化的时候会根据当前系统环境获取 ExtensionFactory,也就是 SpiExtensionFactory 和 SpringExtensionFactory 存到 factories 中。
public AdaptiveExtensionFactory() {
ExtensionLoader ExtensionFactory loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List ExtensionFactory list = new ArrayList ExtensionFactory
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
factories = Collections.unmodifiableList(list);
我们看其中一个 SpiExtensionFactory 的实现,
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public T T getExtension(Class T type, String name) {
if (type.isInterface() type.isAnnotationPresent(SPI.class)) {
ExtensionLoader T loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
return loader.getAdaptiveExtension();
return null;
从 loader.getAdaptiveExtension() 一步步跟进,来到 createAdaptiveExtensionClass(), 创建默认代理类
private Class ? createAdaptiveExtensionClass() {
// 通过反射检测接口方法是否包含 Adaptive 注解
// 构建自适应拓展代码
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
// 获取编译器实现类
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
// 编译代码,生成 Class
return compiler.compile(code, classLoader);
如果你对 createAdaptiveExtensionClass() 生成的代理类感觉有点模糊的话,觉得看代码不清晰,我们可以用阿里开源的工具 arthas 反编译查看一下生成的代理类是什么样子的
由上图可知,生成的代理类从 com.alibaba.dubbo.common.URL 中获取参数实例化并调用接口方法,返回生成的自适应类。
在我们举的例子中,injectExtension(T instance) 的作用就是,生成自适应类 object = Robot$Adaptive,并通过 AdaptiveRobot.setRobot(Robot robot) 注入进去。
5、@Activate 自动激活扩展点
表示实现类是否可以被激活。通常被用在一个接口有很多现实类,但是这些实现类在特定条件才需要使用,比如有些实现只想在生产者生效,有些实现类想在消费者生效。它有两个设置过滤条件的字段,group,value 都是字符数组,用来指定这个扩展类在什么条件下激活。
在 loadClass() 加载扩展类时,把所有实现类中有Activate注解的,放到 cachedActivates 中(忽略点 - 4的解释)
private void loadClass(Map String, Class ? extensionClasses, java.net.URL resourceURL, Class ? clazz, String name) throws NoSuchMethodException {
// ...
if (names != null names.length 0) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
// ...
这篇文章讲解了 Dubbo SPI 的实现机制,关键是要弄懂 @SPI @Adaptive @Activate 注解的含义,知道 Dubbo 中 AOP、IOC 的各自实现,还有就是 SPI 的自适应拓展机制以及 Dubbo 中的 URL 作为配置总线,各个服务的参数配置都是通过 URL 进行传递的。
以上就是Dubbo 源码解析(一)Dubbo SPI(深度剖析dubbo源码)的详细内容,想要了解更多 Dubbo 源码解析(一)Dubbo SPI的内容,请持续关注盛行IT软件开发工作室。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。