二、dubbo spi 源码分析
1、ExtensionLoader
ExtensionLoader 是dubbo spi 主要实现类,从字面意思可以看出是扩展加载器,是将配置文件与java的对应关系进行组装处理,从而得到我们需要的实际扩展处理类
ExtensionLoader 类中有两个静态属性 EXTENSION_LOADERS (缓存所有的ExtensionLoader) 和 EXTENSION_INSTANCES (缓存扩展实现)
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);
1.1 getExtensionLoader 方法
在dubbo源码中获取扩展加载器的主要逻辑是在getExtensionLoader静态方法中
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 an interface!");
}
//判断接口有没有声明@SPI注解
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
//先去缓存中查找有没有对应的扩展类加载器
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;
}
1.2 ExtensionLoader 构造方法 new ExtensionLoader(type)
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
可以看到如果参数type 不是 ExtensionFactory 将会获取ExtensionFactory 的类加载器,接着获取
ExtensionFactory 的自适应扩展类。
ExtensionFactory 到底是什么呢?
@SPI
public interface ExtensionFactory {
/**
* Get extension.
*
* @param type object type.
* @param name object name.
* @return object instance.
*/
<T> T getExtension(Class<T> type, String name);
}
org.apache.dubbo.common.extension.ExtensionFactory 文件中声明了以下SPI 实现:
adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
ExtensionFactory 也是一个被标记的扩展接口,再dubbo 中配置了两个扩展实现。而在dubbo-config-spring 的配置中我们可以找到另一个实现类:
spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory
获取到了ExtensionFactory 的扩展类加载器后,getAdaptiveExtension() 会做哪些事呢?
1.3 getAdaptiveExtension 方法
public T getAdaptiveExtension() {
//缓存中获取自适应扩展实例
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError != null) {
throw new IllegalStateException("Failed to create adaptive instance: " +
createAdaptiveInstanceError.toString(),
createAdaptiveInstanceError);
}
synchronized (cachedAdaptiveInstance) {
//缓存中获取自适应扩展实例
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//创建自适应扩展实例
instance = createAdaptiveExtension();
//放入缓存中
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}
return (T) instance;
}
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
private Class<?> getAdaptiveExtensionClass() {
//根据对应的SPI文件加载扩展类并缓存,细节此处不展开
getExtensionClasses();
// 如果存在被@Adaptive修饰的类则直接返回此类
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
// 动态生成Xxxx$Adaptive类
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
//代理类
package com.jufeng.learn.other.api.dubbo.spi.demo03;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class SimpleEcho$Adaptive implements com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho {
public void printA(java.lang.String arg0) {
throw new UnsupportedOperationException("method public abstract void com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho.printA(java.lang.String) of interface com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho is not adaptive method!");
}
public void printB(com.alibaba.dubbo.common.URL arg0, java.lang.String arg1) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg0;
String extName = url.getParameter("simple.echo");
if(extName == null) throw new IllegalStateException("Fail to get extension(com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho) name from url(" + url.toString() + ") use keys([simple.echo])");
com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho extension = (com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho)ExtensionLoader.getExtensionLoader(com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho.class).getExtension(extName);extension.printB(arg0, arg1);
}
}
至此,自适应扩展类就被加载完成,有兴趣可以看getExtensionClasses 方法是怎么实现读取 SPI配置文件以及 @Adaptive 和 URL 参数的解析校验。
下面一节,我们分析ExtensionFactory 的作用,以及在Dubbo是如何将SpringIOC 容器中的实例整合到Dubbo框架中。
2. ExtensionFactory
ExtensionFactory是dubbo框架中被标记的一个扩展接口,默认实现为AdaptiveExtensionFactory。
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> 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);
}
@Override
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
在无参的构造方法中可以看到,它会获取ExtensionFactory 的扩展类加载器,并将所有的实现类全部放入factories 属性中。而dubbo 以及 dubbo-config-spring 中配置的
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory 都会被放入 factories 中。
SpringExtensionFactory 是我们重点关注的对象,下面看看它的实现:
public class SpringExtensionFactory implements ExtensionFactory {
private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();
public static void addApplicationContext(ApplicationContext context) {
CONTEXTS.add(context);
if (context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) context).registerShutdownHook();
}
}
public static void removeApplicationContext(ApplicationContext context) {
CONTEXTS.remove(context);
}
public static Set<ApplicationContext> getContexts() {
return CONTEXTS;
}
// currently for test purpose
public static void clearContexts() {
CONTEXTS.clear();
}
@Override
@SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
//SPI should be get from SpiExtensionFactory
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
return null;
}
for (ApplicationContext context : CONTEXTS) {
T bean = getOptionalBean(context, name, type);
if (bean != null) {
return bean;
}
}
return null;
}
}
可以看到 SpringExtensionFactory 中维护了Spring上下文对象ApplicationContext,所以只要Spring的上下文对象被放入 SpringExtensionFactory CONTEXTS 属性中,Dubbo 就可以获取到SpringIOC 中的实例。
以ServiceBean 为例,在Dubbo中是对服务提供接口的一次封装,用于注入到Spring中,那么Dubbo 在暴露接口的时候是需要拿到IOC 中的一些实例,所以Dubbo是怎么做的呢?下面来看ServiceBean 的实现
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
}
......
}
可以看到 ServiceBean 实现了 ApplicationContextAware ,而实现了ApplicationContextAware 接口将会在bean 的初始化之前执行,在执行setApplicationContext 方法时,会执行 SpringExtensionFactory.addApplicationContext(applicationContext) 这行代码,所以Spring的上下文对象就会被写入到 SpringExtensionFactory类的静态成员属性中,当dubbo需要取到 Spring IOC 中的对象时就可以根据 AdaptiveExtensionFactory.getExtension()方法进行获取(此处只是举例,在Spring 中 dubbo 的启动方式,服务暴露等详细内容将在其他章节中解析。)