• [Java]Java SPI机制


    基础环境

    JDK 1.8

    概念

    SPI(Service Provider Interface): 服务提供接口,是JDK提供的一种服务加载机制,简单理解就是通过此JDK规范可实现服务的发现并加载。主要有三部分组成:
    Service: 服务,更准确来说是服务定义,可以接口、抽象类,同样可以是普通的类(服务提供者为其子类,不过一般不这么来定义)
    Service Provider: 服务提供者,可以是Service接口实现类,Service抽象类的实现,以及Service类的继承
    ServiceLoader: 一个简单的服务提供者加载工具

    原始的参考资料可参考JDK源码中对java.util.ServiceLoader的描述。
    在这里插入图片描述

    实践

    SPI规范

    1. 配置文件路径: Service Provider声明配置文件必须在META-INF/services 目录下;
    2. 配置文件名称: Service接口、实现类等全限定类名
    3. 配置文件内容:Service实现类(一个实现类一行)
    4. 保证实现类jar包被正确加载(放置classpath中或自定义Class Loader保证加载)
    5. 实现类提供无参构造方法
      参考示例:
      在这里插入图片描述

    SPI设计思想

    面向接口编程、接口隔离原则(ISP)

    代码实践

    项目结构:

    在这里插入图片描述
    在这里插入图片描述

    定义Serivece

    1. 接口cn.com.demo.api.ISpiDemo
    package cn.com.demo.api;
    
    public interface ISpiDemo {
        String name();
        String exec(String msg);
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 抽象类 cn.com.demo.api.AnstractSpiDemo
    package cn.com.demo.api;
    
    public abstract class AnstractSpiDemo {
       public abstract String sayHello();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 普通类 cn.com.demo.api.SpiDemo
    package cn.com.demo.api;
    
    public class SpiDemo {
       public String sayHello(){
           return this.getClass().getSimpleName();
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    定义Serivece Provider

    接口实现类(定义三个)

    cn.com.demo.impl.Hello0ISpiDemo

    package cn.com.demo.impl;
    
    import cn.com.demo.api.ISpiDemo;
    
    public class Hello0ISpiDemo implements ISpiDemo {
       @Override
       public String name() {
           return this.getClass().getSimpleName();
       }
    
       @Override
       public String exec(String msg) {
           return name()+msg;
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    cn.com.demo.impl.Hello1ISpiDemo

    package cn.com.demo.impl;
    
    import cn.com.demo.api.ISpiDemo;
    
    public class Hello1ISpiDemo implements ISpiDemo {
      @Override
      public String name() {
          return this.getClass().getSimpleName();
      }
    
      @Override
      public String exec(String msg) {
          return name()+msg;
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    cn.com.demo.impl.Hello2ISpiDemo

    package cn.com.demo.impl;
    
    import cn.com.demo.api.ISpiDemo;
    
    public class Hello2ISpiDemo implements ISpiDemo {
      @Override
      public String name() {
          return this.getClass().getSimpleName();
      }
    
      @Override
      public String exec(String msg) {
          return name()+msg;
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    META-INF/services/下定义
    文件名:cn.com.demo.api.ISpiDemo
    文件内容:

    cn.com.demo.impl.Hello1ISpiDemo
    cn.com.demo.impl.Hello2ISpiDemo
    
    • 1
    • 2

    在这里插入图片描述
    注意: 这里的cn.com.demo.impl.Hello0ISpiDemo未被定义到services文件中,应用将不会注册此类。

    抽象类实现类

    cn.com.demo.impl.AnstractSpiDemoImpl

    package cn.com.demo.impl;
    
    import cn.com.demo.api.AnstractSpiDemo;
    
    public class AnstractSpiDemoImpl extends AnstractSpiDemo {
       @Override
       public String sayHello() {
           return this.getClass().getSimpleName();
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    META-INF/services/下定义
    文件名:cn.com.demo.api.AnstractSpiDemo
    文件内容:

    cn.com.demo.impl.AnstractSpiDemoImpl
    
    • 1

    在这里插入图片描述

    子类重写

    cn.com.demo.impl.SpiDemoChild

    package cn.com.demo.impl;
    
    import cn.com.demo.api.SpiDemo;
    
    public class SpiDemoChild extends SpiDemo {
        @Override
        public String sayHello() {
            return  this.getClass().getSimpleName();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    META-INF/services/下定义
    文件名:cn.com.demo.api.SpiDemo
    文件内容:

    cn.com.demo.impl.SpiDemoChild
    
    • 1

    在这里插入图片描述

    编写测试应用

    cn.com.demo.app.SpiTest

    package cn.com.demo.app;
    
    import cn.com.demo.api.ISpiDemo;
    import cn.com.demo.api.SpiDemo;
    import cn.com.demo.api.AnstractSpiDemo;
    import lombok.extern.java.Log;
    
    import java.util.ServiceLoader;
    
    @Log
    public class SpiTest {
        public static void main(String[] args) {
            ServiceLoader<ISpiDemo> load = ServiceLoader.load(ISpiDemo.class);
            for (ISpiDemo spiDemo : load) {
                log.info(spiDemo.name()+"-"+spiDemo);
            }
            log.info("------------------------------");
            ServiceLoader<AnstractSpiDemo> loader = ServiceLoader.load(AnstractSpiDemo.class);
            for (AnstractSpiDemo spiDemoC : loader) {
                log.info(spiDemoC.sayHello());
            }
            log.info("------------------------------");
            ServiceLoader<SpiDemo> loader1 = ServiceLoader.load(SpiDemo.class);
            for (SpiDemo spiDemo : loader1) {
                log.info(spiDemo.sayHello());
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    执行结果

    在这里插入图片描述

    扩展使用

    1. 利用spi的加载机制,在Class Loader加载和实例化时,可在静态代码块、非静态代码块、无参构造等处做服务的初始化工作,如JDBC4.0规范之后不再需要Class.forName()来注册驱动就是因为在静态代码块中已经完成了DriverManager.registerDriver(new Driver())。

    代码地址

    spidemo:https://gitcode.net/master336/spidemo/

  • 相关阅读:
    Camera-Related Architecture
    [网鼎杯 2020 朱雀组]Nmap wp
    nodejs的下载安装
    Linux - firewall-cmd 命令添加端口规则不生效排查
    物奇平台耳机复位功能实现
    线程安全问题(模拟取钱案例)
    计算机设计大赛 深度学习实现语义分割算法系统 - 机器视觉
    小目标检测:基于切图检测的yolov5小目标训练
    Socket网络编程,网络原理基本概念
    【Leetcode】2418. Sort the People
  • 原文地址:https://blog.csdn.net/master336/article/details/127779239