Dubbo SPI,ExtensionLoader之getExtension和getAdaptiveExtension的区别与联系

在dubbo中,大量的使用了ExtensionLoader进行接口实现类的扩展,也就是SPI机制,ExtensionLoader会扫描classpath下与扩展接口全路径名一致的配置文件,如下

文件中配置的都是扩展接口的实现类,调用ExtensionLoader的get类方法后,其会读取上述文件中所有的key=value键值对,加载value对应的class,并缓存到本地map中,key对应配置文件中的key,value对应Class对象。

ExtensionLoader提供了两类get方法,getExtension(key)和getAdaptiveExtension()

1.getExtension(key)方法很好理解,从本地map中找到对应key的class对象,通过反射创建该class对象的实例对象并返回

2.getAdaptiveExtension()方法复杂一些,会通过字符串拼接出一个java文件文本,然后通过动态编译以及类加载,将该类文件对应的class载入到内存,该类是一个实现了扩展接口的java类,部分内容如下:

可以看到,类名后面是个Adaptive,再结合方法名getAdaptiveExtension以及下面的方法说明,我们可以知道,生成的类是一个适配器类,完成的仅仅是适配功能,我下面截取生成类文件中的一个方法来作说明:

方法中除了做了一些基本校验外,主要就是一个转发,关键代码已用红框标出,

1).首先获取url,url是在容器启动时从我们配置的<dubbo:reference>或者<dubbo:service>中解析出来的,我随便举个消费者订阅url的例子方便大家理解:consumer://172.31.30.25/org.apache.dubbo.demo.DemoService?application=demo-consumer&check=false&dubbo=2.0.2&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=37740&qos.port=33333&side=consumer&timeout=60000&timestamp=1554189149262可以看到url中包含了许多参数,我这里列举的远远不是全部,很多参数都是可选的,不指定的话dubbo就会给一个默认值),

2).然后对extName取值,再通过上面介绍的getExtension(key)方法获取最终实现类,并调用其对应方法

String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());

这行代码里的”dubbo“表示默认key,哪里来的呢?

在dubbo中,每个可扩展的接口上,都有@SPI注解,其中()内的属性值就是获取实现类的默认key,代表该接口的默认实现类,例如上述的Protocol接口的默认实现类为DubboProtocol

        getAdaptiveExtension()方法的好处在于,可以根据用户配置的<dubbo:reference>或者<dubbo:service>来动态决定实际运行中,使用的是哪种实现类。

        并且,我们也可以根据这个特性来自定义我们的实现类,并按照文件的配置规则进行配置,比如自定义一个Protocol实现类叫com.bowang.dubbo.MyPrototcol implements ,在我们的项目src/main/resources/META-INF/internal下创建一个org.apache.dubbo.rpc.Protocol文件,内容如下

                      myProtocol=com.bowang.dubbo.MyPrototcol

然后在<dubbo:reference>中指定protocol="myProtocol",如此,就可以实现自定义扩展Protocol了

猜你喜欢

转载自blog.csdn.net/wb_snail/article/details/88994723
今日推荐