• 【SPI】浅谈JDK中SPI技术


    SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。

    常见的 SPI 有 JDBC、日志门面接口、Spring、SpringBoot相关starter组件、Dubbo、JNDI等。

    Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。

     

    要使用Java SPI,需要遵循如下约定:
    1、当服务提供者提供了接口的一种具体实现后,在jar包的META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
    2、接口实现类所在的jar包放在主程序的classpath中;
    3、主程序通过java.util.ServiceLoder动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
    4、SPI的实现类必须携带一个不带参数的构造方法。

     示例:

    先创建四个maven项目,分别为spi-inter(定义标准服务接口)、spi-defaultInterImpl(服务提供方提供的默认实现)、spi-myInterImpl(调用方觉得默认实现不好使,自己写的实现)、spi-testSpi。

    在spi-inter 中定义标准服务接口, 然后将项目打包。

    1 package com.demo.spi_inter;
    2 /**
    3  *    服务方定义的标准服务接口
    4  */
    5 public interface Config {
    6     
    7     void loadConfig();
    8 }

    在spi-defaultInterImpl的pom.xml中添加依赖spi-inter,并进行对接口的实现。在src/main/java目录下新建META-INF/services目录,并在services中新建文件,文件名为接口的全限定名,

    如示例:“com.demo.spi_inter.Config”,内容为接口实现类的全限定名。如示例:”com.demo.spi_defaultInterImpl.DefaultInterImpl“。然后将项目打包。

     1 package com.demo.spi_defaultInterImpl;
     2 
     3 import com.demo.spi_inter.Config;
     4 
     5 public class DefaultInterImpl implements Config{
     6 
     7     @Override
     8     public void loadConfig() {
     9         System.out.println("这是对接口的默认实现");
    10     }
    11 
    12 }

    在spi-testSpi的pom.xml文件中添加入spi-defaultInterImpl的依赖。使用 ServiceLoader 来加载配置文件中指定的实现。

     1 package com.demo.spi_testSpi;
     2 
     3 import java.util.Iterator;
     4 import java.util.ServiceLoader;
     5 
     6 import com.demo.spi_inter.Config;
     7 
     8 public class App {
     9     public static void main(String[] args) {
    10         System.out.println("开始加载");
    11         ServiceLoader<Config> loader = ServiceLoader.load(Config.class);
    12         Iterator<Config> iterator = loader.iterator();
    13         while (iterator.hasNext()) {
    14             Config config = (Config) iterator.next();
    15             config.loadConfig();
    16         }
    17     }
    18 }

    运行,可得结果:

    此时,个人调用方觉得默认的实现不太好,于是自己编写了一个新的实现spi-myInterImpl。并创建了相对应的目录结构及文件/META-INF/services/com.demo.spi_inter.Config,文件内容为个人实现的全限定名。打包,将依赖引入到spi-testSpi中。

     1 package com.demo.spi_myInterImpl;
     2 
     3 import com.demo.spi_inter.Config;
     4 
     5 public class MyInterImpl implements Config{
     6 
     7     @Override
     8     public void loadConfig() {
     9         System.out.println("这是个人写的实现");
    10     }
    11 }

    运行spi-testSpi,可以看见控制台输出:

    SPI技术的优劣:

    优点
    解耦,使得第三方服务模块的装配控制的逻辑与调用者的业务代码分离,而不是耦合在一起。应用程序可以根据实际业务情况启用框架扩展或替换框架组件。

    缺点

    虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类。

    多个并发多线程使用ServiceLoader类的实例是不安全的。

    作者:墨猴
    感觉对您有帮助的话,就点个推荐吧!~( ̄▽ ̄)~*
  • 相关阅读:
    持续集成(CI)-概念
    python 多个路由参数传递
    python %s 占位符用法
    本地电脑密钥登陆服务器
    nginx 安装及反向代理、负载均衡、静态文件指向、结合uwsgi上线项目、处理跨域问题
    docker 进入容器
    将python文件变成一个shell脚本可执行文件
    python中quote函数是什么意思,怎么用?
    CentOS 使用 runserver 启动服务器后,常驻后台运行
    Open Set Domain Adaptation by Backpropagation(OSBP)论文数字数据集复现
  • 原文地址:https://www.cnblogs.com/mohou/p/12468074.html
Copyright © 2020-2023  润新知