Dubbo

Dubbo源码分析(五)ExtensionLoader

ExtensionLoader是Dubbo中很有特色的一个设计,它的作用是为框架提供各种组件的扩展点,可以在应用运行时来决定使用哪个组件。对扩展点组件的描述是通过注解的方式实现的,包括3个主要的注解:

  • SPI
  • Adaptive
  • Activate

我们先从注解的含义来理解ExtensionLoader

SPI

SPI是一个很早就存在的概念,它是预先定义的一组接口,并允许各个厂商(使用方)有自己的实现,通过配置的方式在运行时决定使用哪种实现。我们可以看一下Dubbo中具有SPI标记的接口有哪些

  1. CacheFactory
  2. Compiler
  3. ExtensionFactory
  4. LoggerAdapter
  5. Serialization
  6. StatusChecker
  7. DataStore
  8. ThreadPool
  9. Container
  10. PageHandler
  11. MonitorFactory
  12. RegistryFactory
  13. ChannelHandler
  14. Codec
  15. Codec2
  16. Dispatcher
  17. Transporter
  18. Exchanger
  19. HttpBinder
  20. Networker
  21. TelnetHandler
  22. ZookeeperTransporter
  23. ExporterListener
  24. Filter
  25. InvokerListener
  26. Protocol
  27. ProxyFactory
  28. Cluster
  29. ConfiguratorFactory
  30. LoadBalance
  31. Merger
  32. RouterFactory
  33. RuleConverter
  34. ClassNameGenerator
  35. Validation

当我们需这些接口的实现类时,就可以通过ExtensionLoader的方法获取

其中第一个方法是拿到一个具体的实现类,第二个方法是拿到一组被激活的实现类。

Adaptive

这个词无论作为注解名还是get方法名都比较令人迷惑。Adaptive的本意是适配的,之所以这样命名是因为我们从getAdaptiveExtension()获取到的对象并不是某个真正的实现类,而是对实现类进行封装之后的一个适配器。当我们调用这个适配器的方法时,它会间接地去调用具体实现类的方法。而适配器中正包含了该选取何种实现方式的逻辑。

适配器类的定义有两种来源:

  1. 静态代码形式的默认适配器。这些类会被Adaptive注解修饰,且一个接口只能有一个这样的静态适配器。这种形式仅应用于一些特殊的接口,如:AdaptiveCompiler、AdaptiveExtensionFactory这两个适配器,ExtensionLoader需要依赖它们来工作,所以使用了这种特殊的构建方式。
  2. 动态代码适配器。实际上其余的接口都是使用动态适配器,ExtensionLoader根据接口定义动态生成一段适配器代码,并构建这个动态类的实例。这个时候接口中的一些方法具有Adaptive标记,它提供了一些用于查找具体Extension的key,如果这些方法中有URL类型的参数,则会依次在url中查找这些key对应的value,再以此为name确定要使用的Extension。如果没有从url中找到该参数,则会使用SPI注解中的默认值name进行构建。

Transporter

下面以Transporter接口为例进行说明

bind方法具有Adaptive标记,所以在生成动态Adapter类的时候,该方法会根据运行时的参数决定使用那个具体的实现类,以下是部分动态类的代码

在适配器的方法中,首先要确定具体实现类的类型,也就是extName。当方法中有URL类型的参数时,这个配置会从url参数中获取。Adaptive注解中的两个key即是在url查找的key,分别为server和transporter。当两个key都不存在时,使用SPI注解中得默认值netty。在确定了extName后,就可以从事先加载好的实例中获取extension对象,最终将方法的调用传递给extension的对应方法。

全部extName与实现类的对应关系配置在dubbo jar包中MET-INF/dubbo/internal下,Transporter对应的配置文件为

Activate

Activate标记适用于另外一种动态配置

一个接口有多个实现类,Activate标记在每个实现类的type上,并注明“何时被激活”的条件,如group和key的信息,以及在所有被激活实现类中的排序信息。通过ExtensionLoader的getActivateExtension可以获取到被激活实现类构成的List。下面以最重要的Filter接口进行说明

接口本身不再有Activate注解,而是在它的实现类上面,如TimeoutFilter

只有在group为provider时才会生效

MonitorFilter在provider和consumer两端都会生效。这里group、key等条件是通过getActivateExtension的方法参数确定的,group通常是预先设定好的,key可以直接指定,也可以动态由url参数决定。当url中包含特定的key(value可以是任意值)时,对应的实例就会被激活。

ExtensionLoader本身还有很多复杂的实现细节,这里就不再介绍了。感兴趣的读者可以翻阅源码深入研究一下。

 

© 2015, 高飞航.cn. 版权所有.

About gaofeihang

开发工程师,本站的作者。欢迎留下您宝贵的意见!

发表评论

电子邮件地址不会被公开。 必填项已用*标注