DUBBO代码碎片

本文深入剖析DUBBO SPI(Service Provider Interface)机制的核心原理,包括ExtensionLoader的使用方式及扩展点的加载流程,帮助读者理解DUBBO的扩展性和灵活性。

从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!");
}

转载于:https://my.oschina.net/maliang1989/blog/1944722

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值