从DUBBO的启动说起:
public class DemoProvider {
public static void main(String[] args) {
com.alibaba.dubbo.container.Main.main(args);
}
}
进入main方法,首先初始化下面代码:
private static final ExtensionLoader<Container> loader =ExtensionLoader.getExtensionLoader(Container.class);
一句代码即是整个DUBBO SPI的精髓所在,通过ExtensionLoader.getExtensionLoader(Container.class)获取Container(接口)扩展点loader,在通过new ExtensionLoader(Class<?> type)获取扩展点Container的loader时,判断Container非ExtensionFactory.class类型,需要通过下述代码完成ExtensionFactory实例的创建,并赋值给objectFactory (private final ExtensionFactory objectFactory):
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
->ExtensionLoader(Class<?> type)
->getAdaptiveExtension()//获取适配的扩展点实现类实例
->createAdaptiveExtension()//缓存中没有,创建适配的扩展点实现类实例
->getAdaptiveExtensionClass()//获取适配类
->getExtensionClasses()//从约定的配置文件中获取适配类
->loadExtensionClasses()//加载配置类
->loadFile()//从配置文件中加载配置类
->createAdaptiveExtensionClass//约定的配置文件中没有获取到适配类,则需要创建一个适配类
->createAdaptiveExtensionClassCode()//创建适配类的代码
->ExtensionLoader.getExtensionLoader(Compiler.class).getAdaptiveExtension()//获取编译器适配类实例
->compiler.compile(code, classLoader)//编译代码
其中loadFIle()方法会加载META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory下的每一行,例如spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
并通过反射对com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory进行实例化;
- 通过type.isAssignableFrom(clazz)判断SpiExtensionFactory是ExtensionFactory的子类,否则跑出异常。
- 通过clazz.isAnnotationPresent(Adaptive.class)判断SpiExtensionFactory上是否有@Adaptive注解,如果有则将其保存至cachedAdaptiveClass。
- 通过clazz.getConstructor(type)校验是否为AOP增强,即存在参数为其扩展点接口的构造函数,如果存在,将其缓存至Set<Class<?>>数组中,变量为wrappers。
- 如果上述构造方法不存在,则判断其是否存在无参构造。。。
- 最后将其key/value放入extensionClasses缓存中.
//TODO
完成上述初始化后,由于args为null,那么进入main方法后,DUBBO将执行如下代码片段:
public static final String CONTAINER_KEY = "dubbo.container";
if (args == null || args.length == 0) {
String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());
args = Constants.COMMA_SPLIT_PATTERN.split(config);
}
即:读取dubbo.container配置的dubbo容器(至于dubbo.container配置在哪里,此处不细讲,一般从系统变量和环境变量的dubbo.properties.file或者类路径下的dubbo.properties文件中找,DUBBU读取配置文件的代码后续通过debug详细讲解),在classpath下面有一个文件dubbo.properties中记录了dubbo.container=log4j,spring
因此Container(接口)类型的的变量containers中便有了Container扩展点log4j和Spring两个扩展类的实例,通过下面代码添加:
containers.add(loader.getExtension(args[i]))
DUBBO通过下述代码完成启动任务:
for (Container container : containers) {
container.start();
logger.info("Dubbo " + container.getClass().getSimpleName() + " started!");
}