从ExtensionLoader理解Dubbo扩展机制
2017-01-22 15:39 louistz 阅读(471) 评论(0) 编辑 收藏 举报package com.my.spi; public interface Search { public List serch(String keyword); }
package com.xyz.factory; import java.util.Iterator; import java.util.ServiceLoader; import my.xyz.spi.Search; public class SearchFactory { private SearchFactory() { } public static Search newSearch() { Search search = null; ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class); Iterator<Search> searchs = serviceLoader.iterator(); if (searchs.hasNext()) { search = searchs.next(); } return search; } }
-
package my.xyz.test; import java.util.Iterator; import java.util.ServiceLoader; import com.xyz.factory.SearchFactory; import my.xyz.spi.Search; public class SearchTest { public static void main(String[] args) { Search search = SearchFactory.newSearch(); search.serch("java spi test"); } }
Dubbo改进了JDK标准的SPI的以下问题:
- JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
- 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK标准的ScriptEngine,通过getName();获取脚本类型的名称,但如果RubyScriptEngine因为所依赖的jruby.jar不存在,导致RubyScriptEngine类加载失败,这个失败原因被吃掉了,和ruby对应不起来,当用户执行ruby脚本时,会报不支持ruby,而不是真正失败的原因。
- 增加了对扩展点IoC和AOP的支持,一个扩展点可以直接setter注入其它扩展点。
Dubbo提供了一个@SPI 扩展注解,它达到的功能和java的spi一样,不过它的服务发现用的不是 ServiceLoader,而是自己实现的ExtensionLoader.
约定:
在扩展类的jar包内,放置扩展点配置文件:META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。
(注意:这里的配置文件是放在你自己的jar包内,不是dubbo本身的jar包内,Dubbo会全ClassPath扫描所有jar包内同名的这个文件,然后进行合并)
扩展Dubbo的协议示例:
在协议的实现jar包内放置文本文件:META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,内容为:
xxx=com.alibaba.xxx.XxxProtocol |
实现类内容:
package com.alibaba.xxx; import com.alibaba.dubbo.rpc.Protocol; public class XxxProtocol implemenets Protocol { // ... } |
注意: 扩展点使用单一实例加载(请确保扩展实现的线程安全性),Cache在ExtensionLoader中。
ExtensionLoader的实现
ExtensionLoader 通过其loadFile方法,加载 META-INF/internal/ ,MEAT-INF/dubbo/,META-INF/services/目录下的配置文件(接口全名为文件名),将扩展类加载并缓存。
- @SPI注解用在接口上, 来表明接口实现是可扩展的。这种标记有@SPI的接口,就是可扩展点
- 在dubbo中,扩展点默认存在三种实现: Adaptive, Wrapped ,以及normal实现。 其中normal实现就是第三方实现的有特定功能的接口实现。 Adaptive和Wrapped都是对这些normal实现的适配和包装。 Adaptive是某种意义上的集成和适配。Wrapped是包装和代理,有些aop的意思。可以在dubbo源码中找几个默认的adaptive和wrapped实现看看源码。
- 其中扩展点实现类还支持@Activate注解,指明了扩展点实现类被激活的加载条件。
getAdaptiveExtensionClass流程:
1.先找缓存
2.缓存没有,loadExtension From file (只能有一个实现类被@Adaptive标注)
3. loadFile后还是没有,动态生成(Xxx$Adaptive implements Xxx)。(接口方法至少有一个标注了@Adaptive,且只动态生成有标记的方法)