Dubbo Adaptive机制

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

public class ExtensionLoaderTest {

  @Test
  public 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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值