浅谈SPI扩展机制

本文探讨了SPI(Service Provider Interface)扩展机制,详细介绍了JDK、Spring和Dubbo中的实现方式。JDK的SPI通过`ServiceLoader`加载实现类,Spring类似但用于自动配置,Dubbo的SPI增加了依赖注入步骤。SPI作为一种框架扩展手段,允许开发者方便地插入自己的实现。

目录

背景

1、jdk的spi

2、Spring的spi

2、Dubbo的spi

思考


 

背景

    近来看Hasor、Dubbo等框架都说到微内核(Microkernel),想想jdk、srping、dubbo、hasor等都谈SPI,决定随笔记录下各个框架的spi,文章主要谈jdk、spring、dubbo的spi机制,出于目前的水平看来,spi就是一种偷懒方式,框架内都是针对接口编程,而实现自己可做可不做,谁做的好可以插进来就用就完了。

1、jdk的spi

   jdk的spi先说说java.util.ServiceLoader这个类吧,先看看咋用的尝试下spi,

//定义服务提供接口
public interface JdkProvider {
    int calculate(int x,int y);
}
//第一个服务
public class JdkFirstProvider implements JdkProvider {
    public int calculate(int x, int y) {
        System.out.println("JdkFirstProvider给出 2(x+y)");
        return 2*(x+y);
    }
}
//第二个服务
public class JdkSecondProvider implements JdkProvider {
    public int calculate(int x, int y) {
        System.out.println("JdkSecondProvider给出 x+y");
        return x + y;
    }
}
//消费者
public class JdkFirstCustomer {

    public static void main(String[] args) {
        ServiceLoader<JdkProvider> jdkProviders = ServiceLoader.load(JdkProvider.class);
        jdkProviders.forEach(service-> System.out.println(service.calculate(3,8)));
    }
}

附上一个时序图

    jdk的spi大致就是委托ClassLoader去按META-INF/services/(接口全类名)加载各个实现类,之后反射实例化实现类存到map中,并将实例返回客户端。

2、Spring的spi

    尝试下spring的spi

//bean接口
public interface SpringProvider {
    String sayHello();
}
//接口实现1
public class SpringChineseProvider implements SpringProvider {
    @Override
    public String sayHello() {
        return "SpringChineseProvider 大家好!";
    }
}
//接口实现2
public class SpringUSProvider implements SpringProvider {
    @Override
    public String sayHello() {
        return "SpringUSProvider hello everyone";
    }
}
//客户端
public class SpringCustomer {
    public static void main(String[] args) {
        List<SpringProvider> factories = SpringFactoriesLoader.loadFactories(SpringProvider.class, null);
        factories.forEach(factory->{
            System.out.println(factory.sayHello());
        });
    }
}

   详细说了jdk的spi这个就不细说了,也是通过ClassLoader去META-INF/spring.factories加载class,然后反射实例化返回,说说应用吧,像SpringBoot用这种方式去加载一些自动配置类,即引入xx-starter就能够自动向spring容器中注入许多配置好的组件。

2、Dubbo的spi

//注册工厂
public class DubboMultiRegistryFactory extends AbstractRegistryFactory {
    @Override
    protected Registry createRegistry(URL url) {
        return new DubboMultiRegistry(url);
    }
}
//注册
public class DubboMultiRegistry extends MulticastRegistry {
    public DubboMultiRegistry(URL url) {
        super(url);
        System.out.println("自定义注册中心");
    }
}
//客户端
public class TestExtensionLoader {
    public static void main(String[] args) {
        ExtensionLoader<RegistryFactory> loader = ExtensionLoader.getExtensionLoader(RegistryFactory.class);
        RegistryFactory remote = loader.getExtension("multicast1");
        Registry multicast = remote.getRegistry(new URL("multicast1", "224.5.6.7", 1234));
        System.out.println(multicast);
    }
}
//文件全名 META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory 
//文件内容 multicast1=com.zkr.learning.dubbo.ext.register.DubboMultiRegistryFactory 

     可以看到dubbo的spi主要通过ExtensionLoader实现,整个过程大致也是ClassLoader加载META-INF/dubbo下的文件得到class,取得class后反射实例化,不过在这里实例化后多个一步依赖注入的过程,而依赖注入交给了ExtensionFactory,ExtensionFactory做了几种实现其中就包括SpringExtensionFactory,那总结下来也就是1、根据不同Class类型,到指定位置获取class实例化;2、执行注入交给ExtensionFactory。

思考

   好的框架都做了方便的扩展机制,spi只是其中一种方式,其它的还有诸如:BeanPostProcessor让开发者干预到bean的生命周期,ServletContainerInitializer、ServletContextInitializer、WebApplicationInitializer将ServletContext暴露出来,让开发者可以在web应用中对servlet做些额外操作,ConfigurableEnvironment关联MutablePropertySources让开发者实现环境的可动态配置,ChannelHandler、ChannelHandlerContext、ChannelPipeline让开发者对数据的读写能进行自定义的操作,当然还有一些其它的像Flowable的各种引擎配置器,这些都是一些接口,也是一种方式,针对接口编程,当然spi也是接口编程,只是它是找固定位置的文件,其它的可能是做一个循环链式处理,当然在这里也看到了jdk思想的强大,不管啥框架吧,都会借鉴jdk的思想,然后做一些额外的优化,比如上文的3种扩展机制,因此接下来还要好好看看javase、javaee的其它思想。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

&一步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值