在阅读dubbo的源码的时候,下面这行代码或者相似的代码我们会经常看到
ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) .getExtension(url.getProtocol())
这就是dubbo的SPI机制,这种方式我们平时也经常用,使用场景就是,我们定义了一个接口,有好多类实现了这个接口,程序在编写时我们不知道的用户要使用哪个实现类,由用户在配置文件里面指定,等到需要使用的使用,通过反射来获取具体的实现,提高了程序的扩展性。下面我们就来看看dubbo的SPI机制是如何实现的。
可用于SPI的接口都被添加了SPI注解,如下
当我们需要一个接口的具体实现的时候首先会调用
ExtensionLoader.getExtensionLoader(XXXX)
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//如果传入了一个null
if (type == null)
throw new IllegalArgumentException("Extension type == null");
//如果传入的class不是一个接口
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
//如果传入的class没有SPI注解
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);
}
return loader;
}
首先会进行三步检查,在代码里面都注释了,检查通过之后,会尝试从EXTENSION_LOADERS获取当前class的ExtensionLoader,如果没有就新创建一个,再返回。
EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
EXTENSION_LOADERS就是一个map用来保存每个class对应的ExtensionLoader
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
这是ExtensionLoader私有的构造方法,首先保存了当前class,判断当前class是否是ExtensionFactory.class,如果是则保存null,如果不是调用后面的方法,我们可以发现后面的方法有两个,第一步和我们前面进入的方法是一样的,只不过这一次是ExtensionFactory.class,那么这次objectFactory保存的就是null,我们重点看后面这部分方法
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: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
如果不是ExtensionFactory.class,那么objectFactory保存的就是通过createAdaptiveExtension构建的一个对象
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
在这个方法里面,首先调用getAdaptiveExtensionClass()获得一个class并将它实例化当作参数传入injectExtension里卖弄取包装,我们从里往外看
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
首先调用getExtensionClasses方法获取到实现了用户传入接口的所有实现类并保存起来,如果cachedAdaptiveClass不为空就直接返回,否则dubbo自己拼接一个代理类返回
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;
}
调用loadExtensionClasses方法返回实现类的名字和对应的类的map集合
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if (value != null && (value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
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<?>>();
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadFile(extensionClasses, DUBBO_DIRECTORY);
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
在这个方法中最终会调用loadFile方法将指定目录下当前接口对应的文件读入,并获取他们的class对象保存的map中
createAdaptiveExtensionClass方法就是dubbo为添加了SPI注解的接口根据它的方法和方法参数拼接的代理类,从网上copy了一个dubbo生成的代理类如下:
//动态生成的协议代理类
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(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();
//默认选择dubbo协议,否则根据url中带的协议属性来选择对应的协议处理对象,这样可以动态选择不同的协议
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
//根据拿到的协议key从缓存的map中取协议对象
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
//根据拿到的协议key从缓存的map中取协议对象
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}
下面在createAdaptiveExtension方法中就会将这个代理类实例化并传入injectExtension方法中,在里面就是利用反射机制判断接口代理类中是否有需要注入的属性,回退到之前的方法getAdaptiveExtension,将构建的代理类保存到objectFactory中就结束了ExtensionLoader的创建
在dubbo中用户的一切配置都放到了url中,当需要使用接口的某个实现类的时候,首先获取到这个接口对应的ExtensionLoader,然后调用getExtension方法,参数就是url中要使用的实现类的名称
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
return getDefaultExtension();
}
//根据传入的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;
}
private T createExtension(String name) {
//根据参数获取接口的Class对象
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
//判断Map中是否存在改Class的实例
T instance = (T) EXTENSION_INSTANCES.get(clazz);
//创建一个实例并保存到map中
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) 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);
}
}
dubbo的SPI机制差不多就是这些内容了!!!