zoukankan      html  css  js  c++  java
  • 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 作为默认
  • 相关阅读:
    通联支付相关注意事项
    账号配置vue版本的扫码下单以及对店铺进行装修的步骤
    银盒子扫码下单在线订单开启商品售卖时段使用说明
    ERP承接新后台优惠规则问题
    简易付安装后无法使用
    ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证代码篇
    ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证
    ASP.NET没有魔法——ASP.NET MVC 过滤器(Filter)
    ASP.NET没有魔法——ASP.NET Identity与授权
    ASP.NET没有魔法——ASP.NET Identity的加密与解密
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/15396335.html
Copyright © 2011-2022 走看看