栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JDK.Dubbo.Spring的SPI机制对比

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JDK.Dubbo.Spring的SPI机制对比

文章目录
      • 1.JDK SPI
      • 2.Dubbo SPI
      • 3.Spring spi
      • 4.总结

1.JDK SPI

JDK 中 提供了一个 SPI 的功能,核心类是 java.util.ServiceLoader。其作用就是,可以通过类名获取在meta-INF/services/下的多个配置实现文件。

meta-INF/services/下创建一个 com.atguigu.SuperLoggerConfiguration

通过 ServiceLoader 获取我们的 SPI 机制配置的实现类

ServiceLoader serviceLoader = ServiceLoader.load(SuperLoggerConfiguration.class);
Iterator iterator = serviceLoader.iterator();
SuperLoggerConfiguration configuration;

while(iterator.hasNext()) {
    //加载并初始化实现类
    configuration = iterator.next();
}

//对最后一个configuration类调用configure方法
configuration.configure(configFile);

SPI的目的是为了增强扩展性,将固定的配置提取出来,然后通过SPI机制配置。那么既然如此就会有一个默认的配置类。
这样就会出现一个接口多个实现,那么如何找到是哪个实现类呢。

所以使用Iterator获取实现配置。而不是get只获取一个配置类。

所以JDK SPI的一个缺点就是无法确定哪个类的实现,而且没有去重的概念。

2.Dubbo SPI

与 Java SPI 实现类配置不同,Dubbo SPI 是通过键值对的方式进行配置,这样我们可以按需加载指定的实现类。另外在使用时还需要在接口上标注 @SPI 注解。

@SPI
public interface Robot {
    void sayHello();
}

public class OptimusPrime implements Robot {
    
    @Override
    public void sayHello() {
        System.out.println("Hello, I am Optimus Prime.");
    }
}

public class Bumblebee implements Robot {

    @Override
    public void sayHello() {
        System.out.println("Hello, I am Bumblebee.");
    }
}


public class DubboSPITest {

    @Test
    public void sayHello() throws Exception {
        ExtensionLoader extensionLoader = 
            ExtensionLoader.getExtensionLoader(Robot.class);
        Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
        optimusPrime.sayHello();
        Robot bumblebee = extensionLoader.getExtension("bumblebee");
        bumblebee.sayHello();
    }
}

Dubbo spi和JDK spi的区别在于Dubbo spi可以利用别名,可以通过某个扩展点的别名来获取固定的扩展点。
这样就避免了JDK spi中的无法确定是哪一个类实现的配置。

@SPI("dubbo")
public interface Protocol {
    ......
}

通过spi可以确实是别名为dubbo的实现了配置。

filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol


dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol


injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
rest=com.alibaba.dubbo.rpc.protocol.rest.RestProtocol
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
qos=com.alibaba.dubbo.qos.protocol.QosProtocolWrapper

然后只需要通过getDefaultExtension,就可以获取到 @SPI 注解上value对应的那个扩展实现了

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension();

Dubbo 的 SPI 中还有一个“加载优先级”,优先加载内置(internal)的,然后加载外部的(external),按优先级顺序加载,如果遇到重复就跳过不会加载了。

由于有别名的存在所以有去重的概念。

3.Spring spi
meta-INF/spring.factories

主要是在配置文件中将全部的配置类都写在一个配置文件中。和jdk spi不一样的地方。省去了配置一大堆文件的麻烦。

Spring 也是支持 ClassPath 中存在多个 spring.factories 文件的,加载时会按照 classpath 的顺序依次加载这些 spring.factories 文件,添加到一个 ArrayList 中。由于没有别名,所以也没有去重的概念,有多少就添加多少。

但是Spring Boot 中的 ClassLoader 会优先加载项目中的文件,而不是依赖包中的文件。所以如果项目中定义了spring.factories文件,那么项目中的文件会被第一个加载。

如果想扩展某个接口的话,只需要新建meta-INF/spring.factories文件,然后添加配置即可,不用复制以前的再添加新的。

4.总结


三种 SPI 机制对比之下,JDK 内置的机制是最弱鸡的,但是由于是 JDK 内置,所以还是有一定应用场景,毕竟不用额外的依赖;Dubbo 的功能最丰富,但机制有点复杂了,而且只能配合 Dubbo 使用,不能完全算是一个独立的模块;Spring 的功能和JDK的相差无几,最大的区别是所有扩展点写在一个 spring.factories 文件中,也算是一个改进,并且 IDEA 完美支持语法提示。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/659289.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号