• 20211012 Dubbo 的 SPI 和 Adaptive


    准备工作

    定义服务接口:

    package com.lagou.service;
    
    import org.apache.dubbo.common.URL;
    import org.apache.dubbo.common.extension.Adaptive;
    import org.apache.dubbo.common.extension.SPI;
    
    @SPI("human")
    public interface HelloService {
        String sayHello();
    
        @Adaptive
        String sayHello(URL url);
    }
    

    两个接口实现类:

    package com.lagou.service.impl;
    
    import com.lagou.service.HelloService;
    import org.apache.dubbo.common.URL;
    
    public class DogHelloService implements HelloService{
        @Override
        public String sayHello() {
            return "wang wang";
        }
    
        @Override
        public String sayHello(URL url) {
            return "wang url";
        }
    }
    
    package com.lagou.service.impl;
    
    import com.lagou.service.HelloService;
    import org.apache.dubbo.common.URL;
    
    public class HumanHelloService implements HelloService{
        @Override
        public String sayHello() {
            return "hello 你好";
        }
    
        @Override
        public String sayHello(URL url) {
            return  "hello url";
        }
    }
    

    SPI

    定义 SPI 配置文件:META-INF/dubbo/com.lagou.service.HelloService

    human=com.lagou.service.impl.HumanHelloService
    dog=com.lagou.service.impl.DogHelloService
    

    SPI 调用:

    package com.lagou;
    
    import com.lagou.service.HelloService;
    import org.apache.dubbo.common.extension.ExtensionLoader;
    
    import java.util.Set;
    
    public class DubboSpiMain {
        public static void main(String[] args) {
            // 获取扩展加载器
            ExtensionLoader<HelloService> extensionLoader = ExtensionLoader.getExtensionLoader(HelloService.class);
            // 遍历所有的支持的扩展点 META-INF.dubbo
            Set<String> extensions = extensionLoader.getSupportedExtensions();
            for (String extension : extensions) {
                String result = extensionLoader.getExtension(extension).sayHello();
                System.out.println(result);
            }
    
            System.out.println("=================");
    
            // 指定调用
            System.out.println(extensionLoader.getExtension("human").sayHello());
    
        }
    }
    

    Adaptive

    public class DubboAdaptiveMain {
        public static void main(String[] args) {
            URL url = URL.valueOf("test://localhost/hello?hello.service=dog");
            ExtensionLoader<HelloService> extensionLoader = ExtensionLoader.getExtensionLoader(HelloService.class);
            HelloService adaptiveExtension = extensionLoader.getAdaptiveExtension();
            String msg = adaptiveExtension.sayHello(url);
            System.out.println(msg);
        }
    }
    

    分析源码

    生成 Adaptive 类代码:org.apache.dubbo.common.extension.ExtensionLoader#createAdaptiveExtensionClass

    以上面的接口为例,生成的代码是:

    package com.lagou.service;
    
    import org.apache.dubbo.common.extension.ExtensionLoader;
    
    public class HelloService$Adaptive implements com.lagou.service.HelloService {
        public java.lang.String sayHello() {
            throw new UnsupportedOperationException(
                    "The method public abstract java.lang.String com.lagou.service.HelloService.sayHello() of interface com.lagou.service.HelloService is not adaptive method!");
        }
    
        public java.lang.String sayHello(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("hello.service", "human");
            if (extName == null)
                throw new IllegalStateException("Failed to get extension (com.lagou.service.HelloService) name from url ("
                        + url.toString() + ") use keys([hello.service])");
            com.lagou.service.HelloService extension = (com.lagou.service.HelloService) ExtensionLoader
                    .getExtensionLoader(com.lagou.service.HelloService.class).getExtension(extName);
            return extension.sayHello(arg0);
        }
    }
    

    可以看出,Adaptive 类只是做了一个转发,实际还是 SPI 调用,这里转发的工作是获得 SPI 的 key ,也就是按照一定的规则选择 SPI:

    • 如果指定了 @Adaptivevalue ,根据此 value 寻找 URL 上的参数
    • 如果接口方法上未指定 @Adaptivevalue ,会根据类名称按照规则指定,例如 HelloService 默认为 hello.service
    • 如果 URL 的参数上没有 @Adaptive 指定的 key ,使用 @SPIvalue 作为默认
  • 相关阅读:
    研究人员用数据统计的方法来做文学研究
    导致大数据项目失败的4大痛点及应对策略
    导致大数据项目失败的4大痛点及应对策略
    excel怎么制作三维圆环图表
    excel怎么制作三维圆环图表
    ios开发之Swift新手入门
    ZOJ3629 Treasure Hunt IV(找规律,推公式)
    nginx源代码分析--进程间通信机制 &amp; 同步机制
    &lt;LeetCode OJ&gt; 326. Power of Three
    二进制整数的乘除运算
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/15396335.html
Copyright © 2020-2023  润新知