通过示例了解dubbo的SPI机制(1)

129 阅读2分钟

下面示例中,使用@spi、@adaptive、@wrapper,了解其作用

Geek

@SPI("dubbo")
public interface Geek {

    @Adaptive
    String getCourse(URL url);

    @Adaptive({"custom", "geek"})
    String getCourse2(URL url);
}
public class Dubbo implements Geek {

    @Override
    public String getCourse(URL url) {
        return "Dubbo实战进阶课程";
    }

    @Override
    public String getCourse2(URL url) {
        return "Dubbo实战进阶课程(2)";
    }
}
public class SpringCloud implements Geek {

    @Override
    public String getCourse(URL url) {
        return "SpringCloud入门课程100集";
    }

    @Override
    public String getCourse2(URL url) {
        return "SpringCloud入门课程100集(2)";
    }
}

wrapper

@Wrapper(order = 10, mismatches = {"springcloud"})
public class GeekWrapper implements Geek {

    private Geek geek;
    private Animal monkey;

    public void setMonkey(Animal monkey){
        this.monkey = monkey;
    }

    public GeekWrapper(Geek geek) {
        this.geek = geek;
    }

    @Override
    public String getCourse(URL url) {
        return "【课程GeekWrapper前...】" + geek.getCourse(url) + "【课程GeekWrapper后...】||【"+monkey.eat(url)+"】";
    }

    @Override
    public String getCourse2(URL url) {
        return "【课程2前...】" + geek.getCourse2(url) + "【课程2后...】";
    }
}
@Wrapper(order = 1)
public class AppleWrapper implements Geek {

    private Geek geek;

    public AppleWrapper(Geek geek) {
        this.geek = geek;
    }

    @Override
    public String getCourse(URL url) {
        return "【课程AppleWrapper前...】" + geek.getCourse(url) + "【课程AppleWrapper后...】";
    }

    @Override
    public String getCourse2(URL url) {
        return "【课程2前...】" + geek.getCourse2(url) + "【课程2后...】";
    }
}

adaptive,作用在方法上,会根据javassist生成动态类

@SPI("monkey")
public interface Animal {

    @Adaptive
    String eat(URL url);
}
public class Monkey implements Animal{

    @Override
    public String eat(URL url) {
        return "猴子吃香蕉";
    }
}

配置文件

application.properties

server.port=8180

META—INF.dubbo下的spi文件

com.hmilyylimh.cloud.inject.spi.Animal

monkey=com.hmilyylimh.cloud.inject.spi.Monkey

com.hmilyylimh.cloud.inject.spi.Geek

dubbo=com.hmilyylimh.cloud.inject.spi.Dubbo
springcloud=com.hmilyylimh.cloud.inject.spi.SpringCloud
com.hmilyylimh.cloud.inject.spi.GeekWrapper
com.hmilyylimh.cloud.inject.spi.AppleWrapper

测试入口

public class Dubbo18DubboInjectApplication {

    public static void main(String[] args) {
        ApplicationModel applicationModel = ApplicationModel.defaultModel();
        // 通过 Geek 接口获取指定像 扩展点加载器
        ExtensionLoader<Geek> extensionLoader = applicationModel.getExtensionLoader(Geek.class);

        Geek geek = extensionLoader.getAdaptiveExtension();
        System.out.println("日志1:【指定的 geek=springcloud 的情况】动态获取结果为: "
                + geek.getCourse(URL.valueOf("xyz://127.0.0.1/?geek=springcloud")));
        System.out.println("日志2:【指定的 geek=dubbo 的情况】动态获取结果为: "
                + geek.getCourse(URL.valueOf("xyz://127.0.0.1/?geek=dubbo")));
        System.out.println("日志3:【不指定的 geek 走默认情况】动态获取结果为: "
                + geek.getCourse(URL.valueOf("xyz://127.0.0.1/")));
    }
}

通过adaptive动态生成的代理类,反编译代码如下,底层还是依赖getExtension方法

public class Geek$Adaptive implements com.hmilyylimh.cloud.inject.spi.Geek {
    public java.lang.String getCourse(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("geek", "dubbo");
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (com.hmilyylimh.cloud.inject.spi.Geek) name from" +
                    " url (" + url.toString() + ") use keys([geek])");
        ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(),
                com.hmilyylimh.cloud.inject.spi.Geek.class);
        com.hmilyylimh.cloud.inject.spi.Geek extension =
                (com.hmilyylimh.cloud.inject.spi.Geek) scopeModel.getExtensionLoader(com.hmilyylimh.cloud.inject.spi.Geek.class).getExtension(extName);
        return extension.getCourse(arg0);
    }

    @Override
    public String getCourse2(URL url) {
        return null;
    }
}