当前位置: 代码迷 >> 综合 >> Dubbo Adaptive机制
  详细解决方案

Dubbo Adaptive机制

热度:67   发布时间:2023-09-23 13:23:00.0

参考链接
就是说可以根据你传进来的参数进行实例化相应的类。
使用:在方法上增加一个URL参数

public class ExtensionLoaderTest {
    @Testpublic void testGetExtensionLoader() {
    // 首先创建一个模拟用的URL对象URL url = URL.valueOf("dubbo://192.168.0.101:20880?fruit.granter=apple");// 通过ExtensionLoader获取一个FruitGranter对象FruitGranter granter = ExtensionLoader.getExtensionLoader(FruitGranter.class).getAdaptiveExtension();// 使用该FruitGranter调用其"自适应标注的"方法,获取调用结果String result = granter.watering(url);System.out.println(result);}
}

上述代码中,我们首先模拟构造了一个URL对象,这个URL对象是Dubbo中进行参数传递所使用的一个基础类,在配置文件中配置的属性都会被封装到该对象中。这里我们主要要注意该对象是通过一个url构造的,并且url的最后我们有一个参数fruit.granter=apple,这里其实就是我们所指定的使用哪种基础服务类的参数。比如这里指定的就是使用apple对应的AppleGranter。

在构造一个URL对象之后,我们通过ExtensionLoader.getExtensionLoader(FruitGranter.class)方法获取了一个FruitGranter对应的ExtensionLoader对象,然后调用其getAdaptiveExtension()方法获取其为FruitGranter接口构造的子类实例,这里的子类实际上就是ExtensionLoader通过一定的规则为FruitGranter接口编写的子类代码,然后通过javassist或jdk编译加载这段代码,加载完成之后通过反射构造其实例,最后将其实例返回。在上面我们调用该实例,也就是granter对象的watering()方法时,该方法内部就会通过url对象指定的参数来选择具体的实例,从而将真正的工作交给该实例进行。通过这种方式,Dubbo SPI就实现了根据传入参数动态的选用具体的实例来提供服务的功能。如下是该ExtensionLoader为FruitGranter动态生成的子类
代码:

package org.apache.dubbo.demo.example.eg19;import org.apache.dubbo.common.extension.ExtensionLoader;public class FruitGranter$Adaptive implements org.apache.dubbo.demo.example.eg19.FruitGranter {
    public org.apache.dubbo.demo.example.eg19.Fruit grant() {
    throw new UnsupportedOperationException("The method public abstract org.apache.dubbo.demo.example.eg19.Fruit " + "org.apache.dubbo.demo.example.eg19.FruitGranter.grant() of interface " + "org.apache.dubbo.demo.example.eg19.FruitGranter is not adaptive method!");}public java.lang.String watering(org.apache.dubbo.common.URL arg0) {
    if (arg0 == null) {
    throw new IllegalArgumentException("url == null");}org.apache.dubbo.common.URL url = arg0;String extName = url.getParameter("fruit.granter", "apple");if (extName == null) {
    throw new IllegalStateException("Failed to get extension (org.apache.dubbo.demo.example.eg19.FruitGranter) name " + "from url (" + url.toString() + ") use keys([fruit.granter])");}org.apache.dubbo.demo.example.eg19.FruitGranter extension =(org.apache.dubbo.demo.example.eg19.FruitGranter) ExtensionLoader.getExtensionLoader(org.apache.dubbo.demo.example.eg19.FruitGranter.class).getExtension(extName);return extension.watering(arg0);}
}

关于该生成的代码,我们主要要注意如下几个问题:

所有未使用@Adaptive注解标注的接口方法,默认都会抛出异常;
在使用@Adaptive注解标注的方法中,其参数中必须有一个参数类型为URL,或者其某个参数提供了某个方法,该方法可以返回一个URL对象;
在方法的实现中会通过URL对象获取某个参数对应的参数值,如果在接口的@SPI注解中指定了默认值,那么在使用URL对象获取参数值时,如果没有取到,就会使用该默认值;
最后根据获取到的参数值,在ExtensionLoader中获取该参数值对应的服务提供类对象,然后将真正的调用委托给该服务提供类对象进行;
在通过URL对象获取参数时,参数key获取的对应规则是,首先会从@Adaptive注解的参数值中获取,如果该注解没有指定参数名,那么就会默认将目标接口的类名转换为点分形式作为参数名,比如这里FruitGranter转换为点分形式就是fruit.granter。

  相关解决方案