提到dubbo必須提到SPI。網(wǎng)絡(luò)上有很多介紹SPI原理的文章,我不多介紹了。我介紹一下SPI的流程。官方文檔介紹:
http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html
SPI提供了一種插件功能,對(duì)于服務(wù)組件可以替換。dubbo的各層中,除了服務(wù)代理層和配置層之外,其他層組件都可以使用SPI替換。
下面的流程圖以代碼ExtensionLoader.getExtensionLoader(Container.class).getExtension("spring")為例。

上圖中提到的搜索文件和目錄可以參考代碼ExtensionLoader.loadExtensionClasses,這個(gè)方法指定了搜索目錄:
META-INF/dubbo/internal/
META-INF/dubbo/
META-INF/services/
搜索的文件名為ExtensionLoader.getExtensionLoader方法入?yún)⒌娜薅惷?。例如入?yún)ontainer.class,那么對(duì)應(yīng)的文件名是org.apache.dubbo.container.Container。
當(dāng)我們要搜索的內(nèi)容不在文件中時(shí),比如搜索數(shù)據(jù)庫(kù),可以重寫loadExtensionClasses方法查詢數(shù)據(jù)庫(kù)。不過這樣我們需要修改源代碼。
文件org.apache.dubbo.container.Container里面的內(nèi)容如下:
spring=org.apache.dubbo.container.spring.SpringContainer
log4j=org.apache.dubbo.container.log4j.Log4jContainer
logback=org.apache.dubbo.container.logback.LogbackContainer
方法getExtension的入?yún)⑹俏募锩婷恳恍械忍?hào)前面的值。
方法getExtensionLoader的入?yún)榻涌?,要使用SPI加載對(duì)象,接口必須有SPI注解。SPI注解的value值表示要加載對(duì)象的默認(rèn)名字??梢允褂胓etDefaultExtension方法加載默認(rèn)名字對(duì)應(yīng)的對(duì)象。比如Container接口默認(rèn)對(duì)象名字是spring,如果使用getDefaultExtension方法加載對(duì)象,那么和getExtension("spring")加載的對(duì)象是一樣的。
除了getDefaultExtension,getExtension方法,還有g(shù)etActivateExtension和getAdaptiveExtension。
getActivateExtension可以加載多個(gè)對(duì)象,可以參考接口Filter。要求接口的實(shí)現(xiàn)類必須有Activate注解,如果注解的value和group與getActivateExtension入?yún)⒁恢拢敲磄etActivateExtension方法會(huì)返回一個(gè)List集合。
getAdaptiveExtension方法一般會(huì)通過代碼生成模塊生成一個(gè)Adaptive類型的類,并實(shí)例化對(duì)象。代碼生成是AdaptiveClassCodeGenerator類完成的。Adaptive類型的類方法需要有Adaptive注解,沒有Adaptive注解的方法在自動(dòng)生成的代碼里面會(huì)拋出UnsupportedOperationException。Adaptive類型的對(duì)象是自適應(yīng)對(duì)象,Adaptive注解的方法入?yún)⑹荱RL或者包含URL屬性的對(duì)象,Adaptive注解的value值為URL的屬性名,屬性名對(duì)應(yīng)的值就是要加載的對(duì)象名,如果URL中不包含Adaptive注解指定的值,那么使用Adaptive類型類的接口的SPI注解的value值作為默認(rèn)值。