JAVA SPI 是怎么实现的?

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: JAVA SPI 是怎么实现的?

JAVA SPI  是怎么实现的?



SPI 是什么?


SPI(Service Provider Interface) ,是 JDK 内置的一种提供发现机制。SPI 是一种动态替换发现的机制。


640.png


JAVA SPI 实现

  1. 定义一组接口,接口有多种实现
public interface IShout {
    void shout();
}
public class Cat implements IShout {
    @Override
    public void shout() {
        System.out.println("miao miao");
    }
}
public class Dog implements IShout {
    @Override
    public void shout() {
        System.out.println("wang wang");
    }
}
  1. 在 src/main/resources/ 下建立 /META-INF/services 目录, 新增一个以接口命名的文件 (org.foo.demo.IShout文件),内容是要应用的实现类(这里是org.foo.demo.animal.Dog和org.foo.demo.animal.Cat,每行一个类)。

文件位置


- src
    -main
        -resources
            - META-INF
                - services
                    - org.foo.demo.IShout

文件内容

org.foo.demo.animal.Dog
org.foo.demo.animal.Cat
  1. ServiceLoaader 加载配置文件中指定的实现
public class SPIMain {
    public static void main(String[] args) {
        ServiceLoader<IShout> shouts = ServiceLoader.load(IShout.class);
        for (IShout s : shouts) {
            s.shout();
        }
    }
}

输出:


wang wang
miao miao

Java SPI  实现原理


  1. 应用程序调用 ServiceLoader.load 方法创建一个 ServiceLoader,并实例化类中的成员变量。
  • load(Classloader 类型,类加载器)
  • acc(AccessControlContext 类型,访问控制器)
  • providers(LinkedHashMap<String,S>)类型,用于缓存加载成功的类
  • lookupIterators (实现迭代器功能)


private ServiceLoader(Class<S> svc, ClassLoader cl) {
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        reload();
    }
 public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }
  1. 应用程序通过迭代器接口 读取META-INF/services/下的配置文件,然后实例化:

1).读取配置文件


if (configs == null) {
                try {
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }

2). 通过反射方法Class.forName()加载类对象,并用instance()方法将类实例化。

3). 把实例化后的类缓存到providers对象中


JAVA  SPI 应用场景


数据库DriverManager、Spring、ConfigurableBeanFactory等都用到了SPI机制。

在JDBC4.0之前,连接数据库的时候,通常会用Class.forName("com.mysql.jdbc.Driver")这句先加载数据库相关的驱动,然后再进行获取连接等的操作。而JDBC4.0之后不需要Class.forName来加载驱动,直接获取连接即可,这里使用了Java的SPI扩展机制来实现。


  1. 在mysql-connector-java-5.1.45.jar中,META-INF/services目录下会有一个名字为java.sql.Driver的文件:
com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver
  1. Mysql DriverManager实现

DriverManager中有一个静态代码块如下:


static {
  loadInitialDrivers();
  println("JDBC DriverManager initialized");
}

loadInitialDrivers方法,loadInitialDrivers用法用到了上文提到的spi工具类ServiceLoader:


public void run() {
        ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
        Iterator<Driver> driversIterator = loadedDrivers.iterator();
...
}


总结


Java的SPI机制就是为某个接口寻找到相关的服务实现

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4月前
|
XML Java 数据库连接
解码Java SPI:深入理解与实践【七】
解码Java SPI:深入理解与实践【七】
50 0
|
20天前
|
Java 数据库连接 数据库
Java服务提供接口(SPI)的设计与应用剖析
Java SPI提供了一种优雅的服务扩展和动态加载机制,使得Java应用程序可以轻松地扩展功能和替换组件。通过合理的设计与应用,SPI可以大大增强Java应用的灵活性和可扩展性。
47 18
|
1月前
|
Dubbo Java 关系型数据库
Java SPI机制分析
文章深入分析了Java SPI机制,以JDBC为例,详细探讨了服务提供者接口的发现、加载过程,并提供了一个序列化服务的实战示例,展示了如何使用ServiceLoader进行服务发现和扩展。
17 3
|
1月前
|
Java 开发者
Java SPI机制大揭秘:动态加载服务提供者,一文让你彻底解锁!
【8月更文挑战第25天】Java SPI(服务提供者接口)是一种强大的扩展机制,允许程序在运行时动态加载服务实现。本文首先介绍SPI的基本原理——定义接口并通过配置文件指定其实现类,随后通过示例演示其实现过程。接着,对比分析了SPI与反射及插件机制的不同之处,强调SPI在灵活性与扩展性方面的优势。最后,基于不同场景推荐合适的选择策略,帮助读者深入理解并有效利用SPI机制。
44 1
|
28天前
|
开发者 C# 自然语言处理
WPF开发者必读:掌握多语言应用程序开发秘籍,带你玩转WPF国际化支持!
【8月更文挑战第31天】随着全球化的加速,开发多语言应用程序成为趋势。WPF作为一种强大的图形界面技术,提供了优秀的国际化支持,包括资源文件存储、本地化处理及用户界面元素本地化。本文将介绍WPF国际化的实现方法,通过示例代码展示如何创建和绑定资源文件,并设置应用程序语言环境,帮助开发者轻松实现多语言应用开发,满足不同地区用户的需求。
38 0
|
2月前
|
Java Spring 容器
Java中套路和实现问题之基于SPI机制的套路有哪些关键点
Java中套路和实现问题之基于SPI机制的套路有哪些关键点
|
1月前
|
Java 数据库连接 API
Java 的 SPI 机制
Java 的 SPI 机制
22 0
|
3月前
|
监控 Dubbo Java
深入理解Java SPI:服务发现与扩展的利器(一)
深入理解Java SPI:服务发现与扩展的利器(一)
|
4月前
|
Java 关系型数据库 MySQL
【Java——SPI机制详解】
SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL和PostgreSQL都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是 解耦。 当服务的提供者提供了一种接口的实现之后,需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的
132 1
|
Java 数据库连接 开发者
玩转Java面试-什么是Java的SPI机制?
Java的SPI(Service Provider Interface)机制是一种面向接口编程的扩展机制,用于在运行时动态加载实现类。