SPI的简单介绍

1:SPI是什么

首先,SPI是jdk制定的一种规范 ,满足服务使用者在符合开闭原则基础上来编写代码,而能能够实现使用不同的服务提供方提供的服务,既然是规范肯定就需要有接口,而后还要有接口的具体实现,以及具体实现如何暴露给使用者,最后使用者如何使用这些具体实现,都会在SPI中进行制定。如数据库驱动,日志等,有些抽象,接下里使用一个实例来进行说明其具体的使用方法。

2:实例-搭建项目

本例子会采用maven父子项目方式创建5个项目(模块),分别如下:

1:spiparent,作为父项目。
2:spiinterface,指定spi规范的接口,简单定义一个sayHi的方法。
3:spiconcrete-english,实现spiinterface中的接口,实现方式为使用英语sayHi。
4:spiconcrete-chinese,实现spiinterface的接口,实现方式为使用汉语sayHi。
5:spi-invoker,spiconcrete-english和spiconcrete-chinese的具体使用者。

先看最终项目创建完毕结构:
SPI的简单介绍_第1张图片

2.1:创建spiparent

  • new->project
    在这里插入图片描述
  • 选择maven,不勾选Create from archetype
    SPI的简单介绍_第2张图片
  • 输入GAV信息
    SPI的简单介绍_第3张图片
  • next,输入项目名称
    一般和Artifactid保持一致,因此可不做修改。
    SPI的简单介绍_第4张图片
  • finish
    SPI的简单介绍_第5张图片
  • 删除src
    因为作为父项目存在,所以只需要保留pom.xml,不需要源代码文件和资源文件等,因此直接删除src
    在这里插入图片描述

2.2:创建spiinterface

  • 鼠标选中spiparent
  • new->module
    在这里插入图片描述
  • 选择maven,不选择Create from archetype
    SPI的简单介绍_第6张图片
  • 输入ArtifactId为spiinterface
    SPI的简单介绍_第7张图片
  • next->finish
    SPI的简单介绍_第8张图片

2.3:创建spiconcrete-english

2.2,只不过ArtifactId=spiconcrete-english,设置完如下:
SPI的简单介绍_第9张图片

2.4:创建spiconcrete-chinese

2.2,只不过ArtifactId=spiconcrete-chinese,设置完如下:
SPI的简单介绍_第10张图片

2.5:创建spi-invoker

2.2,只不过ArtifactId=spi-invoker,设置完如下:
SPI的简单介绍_第11张图片

3:实例-写代码

3.1:在spiinterface定义接口

public interface SayHi {
    void sayHi();
}

3.2:在spiconcrete-chinese实现接口

  • 引入依赖项目spiinterface
  <dependencies>
    <dependency>
      <groupId>dongshi.daddygroupId>
      <artifactId>spiinterfaceartifactId>
      <version>1.0-SNAPSHOTversion>
    dependency>
  dependencies>
  • 实现接口
public class ChineseSayHi implements SayHi {

    public void sayHi() {
        System.out.println("你好,欢迎来到叶寨村!!!");
    }
}
  • 定义services
    做法为在资源文件夹下创建META-INF/services文件夹,然后创建名称为SPI接口全限定名的文件,并将ChineseSayHi全限定名写到文件中,如下:
    SPI的简单介绍_第12张图片
dongshi.daddy.ChineseSayHi

3.3:在spiconcrete-english实现接口

  • 引入依赖项目spiinterface
  <dependencies>
    <dependency>
      <groupId>dongshi.daddygroupId>
      <artifactId>spiinterfaceartifactId>
      <version>1.0-SNAPSHOTversion>
    dependency>
  dependencies>
  • 实现接口
public class EnglishSayHi implements SayHi {

    public void sayHi() {
        System.out.println("welcome to yezhaicun country!!!");
    }
}
  • 定义services
    做法为在资源文件夹下创建META-INF/services文件夹,然后创建名称为SPI接口全限定名的文件,并将EnglishSayHi全限定名写到文件中,如下:
    SPI的简单介绍_第13张图片
dongshi.daddy.EnglishSayHi

4:实例-测试

具体使用会用到SPI规范中提供的工具类java.util.ServiceLoader,该工具类专门用来从classpath下的META-INF/services下加载对应的具体服务的实现。

4.1:在spi-invoker编写测试类

  • 引入依赖(先使用spiconcrete-chinese
  <dependencies>
    <dependency>
      <groupId>dongshi.daddygroupId>
      <artifactId>spiinterfaceartifactId>
      <version>1.0-SNAPSHOTversion>
    dependency>
    <dependency>
      <groupId>dongshi.daddygroupId>
      <artifactId>spiconcrete-chineseartifactId>
      <version>1.0-SNAPSHOTversion>
    dependency>
  dependencies>
  • 测试代码
public class SayHiTestMain {

    public static void main(String[] args) {
        ServiceLoader<SayHi> load = ServiceLoader.load(SayHi.class);
        for (SayHi sayHi : load) {
            sayHi.sayHi();
        }
    }
}

  • 运行
你好,欢迎来到叶寨村!!!

如果此时我们想要使用英语来sayHi,怎么办呢?只需要将spiconcrete-chinese换为spiconcrete-english的依赖即可,如下:

  <dependencies>
    <dependency>
      <groupId>dongshi.daddygroupId>
      <artifactId>spiinterfaceartifactId>
      <version>1.0-SNAPSHOTversion>
    dependency>
    <dependency>
      <groupId>dongshi.daddygroupId>
      <artifactId>spiconcrete-englishartifactId>
      <version>1.0-SNAPSHOTversion>
    dependency>
  dependencies>
  • 再次运行
welcome to yezhaicun country!!!

满足了开闭原则

5:源码

这里。

6:在数据库驱动中应用

数据库在计算机领域具有非常重要的地位,因此对于数据相关的驱动则无疑是更加重要的,因为我们使用操作数据库必须依赖于这些驱动程序,因此驱动领域中的规范就显的尤为的重要了,对于此,jdk大佬们基于SPI的规范定义了数据库驱动的规范接口,该接口是java.sql.Driver,具体定义如下:

package java.sql;
public interface Driver {
}

接下来以mysql驱动程序为例进行说明。如下是MySQL数据库驱动包截图,可以看到里面定义了META-INF/services/java.sql.Driver文件,内容为该类的具体实现类:
SPI的简单介绍_第14张图片

com.mysql.jdbc.Driver

com.mysql.jdbc.Driver类定义如下:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

可以看到其实现了数据库驱动SPI规范接口java.sql.Driver

最后:都让开,我要喝瑞幸

SPI的简单介绍_第15张图片

你可能感兴趣的:(杂,java,spi,jdk)