dubbo系列之SPI机制实现

dubbo系列之SPI机制实现

从这篇博客开始系统学习一下dubbo源码,相信能收获颇丰。

参考

初识SPI

SPI设计目标

面向对象的设计里,模块之间是基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可插拔的原则,如需要替换一种实现,就需要替换代码。为了实现在模块装配的时候,不在模块里面写代码,这就需要一种服务发现机制。java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到代码之外。

dubbo SPI和 java SPI的不同之处

1:JDK标准得SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。

2:dubbo SPI中增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其他扩展点。

dubbo SPI 约定

spi 文件 存储路径 在 META-INF\dubbo\internal 目录下 并且文件名为接口的全路径名 就是=接口的包名+接口名

每个spi 文件里面的格式定义为: 扩展名=具体的类名,例如 dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。这和jdk SPI的区别就是多了——”扩展名=“,也正是通过这个”扩展名=“,也就是key,实现了只需对key相同的扩展点进行加载。

dubbo SPI的目的:获取一个实现类的对象.

源码构成

运行dubbo源码先找到入口,也就是主函数,dubbo源码的入口就是Main类

Main()——主函数

1
2
3
4
5
6
7
8
9
10
package com.alibaba.dubbo.container;
//...
/**
* Main. (API, Static, ThreadSafe)
*/
public class Main {
//...
private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);//由此进入ExtensionLoader类
//...
}

ExtensionLoader类

getExtensionLoader(Class type) ——为该接口new一个ExtensionLoader,然后缓存起来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
//从缓存中获取ExtensionLoader对象
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);//创建ExtensionFactory对象
}
return loader;
}
1
2
3
4
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
执行以上代码完成了两个属性的初始化

1:每一个ExtensionLoader都包含了两个值type和objectFactory

Class<?> type;//构造器 初始化时要得到的接口名

ExtensionFactory objectFactory// 构造器 初始化时AdaptiveExtensionFactory[SpiExtensionFactory,SpringExtensionFactory]

2:new 一个ExtensionLoader 存储在ConcurrentMap<Class, ExtensionLoader> EXTENSION_LOADERS

关于这个objectFactory的一些细节

1:objectFactory就是ExtensionFactory,它也是通过 ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())来实现的,但是它的objectFactory=null

2:objectFactory的作用:为dubbo的IOC提供所有对象

@Adaptive注解介绍

adaptive注解在类和方法上的区别:

1:注解在类上:代表人工实现编码,即实现了一个装饰类(设计模式中的装饰模式),例如:ExtensionFactory

2:注解在方法上:代表自动生成和编译一个动态的adpative类,例如:Protocol$Adaptive

getAdaptiveExtension()—— 获取一个扩展类,如果@Adaptive注解在类上就是一个装饰类;如果注解在方法上就是一个动态代理类,例如Protocol$Adaptive对象

我们桶Protocol()类进入这个方法,DubboNamespaceHandler类——ServiceBean类——ServiceConfig类,就能看见Protocol()类调用getAdaptiveExtension(),运行DubboDemoProvider类,断点进入getAdaptiveExtension方法

1
2
// Dubbo中Protocol的第一行代码
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
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 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: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}

return (T) instance;
}
ExtensionLoader.loadFile()——getAdaptiveExtension()调用的方法,用于加载配置文件

目的:通过把配置文件META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol的内容,存储在缓存变量里面。

cachedAdaptiveClass//如果这个class含有adaptive注解就赋值,例如ExtensionFactory,er例如Protocol在这个环节是没有的

cachedWrapperClasses//只有该class无adaptive注解,并且构造函数包含目标接口(type)类型,例如protocol里面的spi就只有ProtocolFilterWrapper和ProtocolListenerWrapper能命中

cachedActivates//剩下的类,包含Axtivate注解

cachedNames//最后剩余的类就存储在这里

ExtensionLoader.createAdaptiveExtensionClass()——自动生成和编译一个动态的adpative类——ProxyFactory$Adaptive,这个类是一个代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;

public class ProxyFactory$Adaptive implements com.alibaba.dubbo.rpc.ProxyFactory {

public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");

com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");

if(extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
//通过ExtensionLoaderdubbo的spi获取实现类
com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0);
}

public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2)
throws com.alibaba.dubbo.rpc.RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");

com.alibaba.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");

if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
//通过ExtensionLoader获取实现类
com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getInvoker(arg0, arg1, arg2);
}
}

getExtension()——获取一个指定对象
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 getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
return getDefaultExtension();
}
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;
}