[Spring ~松耦合的设计神器]`SPI`

简介: [Spring ~松耦合的设计神器]`SPI`

Java SPI(Service Provider Interface)是一种Java的服务提供者接口机制。它允许在运行时动态加载实现服务接口的类。


基本概念

SPI 机制的基本思想是,定义一个服务接口,多个不同的实现类可以实现这个接口。然后,在classpath 路径下的META-INF/services目录中创建一个以服务接口的全限定名命名的文件,文件内容为实现类的全限定名。这样,当程序运行时,可以通过ServiceLoader工具类来加载所有实现了该服务接口的类。

使用Java SPI的好处是,可以在不修改源代码的情况下,通过配置更换实现类,实现程序的可扩展性。而不需要在代码中显式地引用实现类,从而实现了松耦合的设计。

SPI机制在Java中被广泛应用,例如JDBC中的Driver接口和Servlet容器中的Servlet接口等。通过SPI机制,可以在不同的场景中灵活地替换实现类,提供更多的选择和定制化的功能。同时,SPI机制也增加了程序的灵活性和可维护性。

最简单的实例

我们现在需要使用一个内容搜索接口,搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索,甚至是 rpc 搜索。

基本步骤

  1. 定义接口
  2. META-INF/services 目录下,新建接口全限定名(如果是内部接口或内部类需要使用 $)的文件,然后在文件里面加上实现类。
  3. 使用 ServiceLoader加载接口,进行使用
public class SpiApplication {
    public interface Search {
        List<String> searchDoc(String keyword);
    }
    public static class FileSearch implements Search{
        @Override
        public List<String> searchDoc(String keyword) {
            System.out.println("文件搜索 "+keyword);
            return null;
        }
    }
    public static class DatabaseSearch implements Search{
        @Override
        public List<String> searchDoc(String keyword) {
            System.out.println("数据搜索 "+keyword);
            return null;
        }
    }
    public static class RpcSearch implements Search{
        @Override
        public List<String> searchDoc(String keyword) {
            System.out.println("rpc搜索 "+keyword);
            return null;
        }
    }
    public static void main(String[] args) {
        ServiceLoader<Search> s = ServiceLoader.load(Search.class);
        Iterator<Search> iterator = s.iterator();
        while (iterator.hasNext()) {
            Search search =  iterator.next();
            search.searchDoc("hello world");
        }
    }
}

可以看到输出三行搜索结果,这就是因为 ServiceLoader.load(Search.class) 在加载某接口时,会去 META-INF/services 下找接口的全限定名文件,再根据里面的内容加载相应的实现类。

这就是 spi 的思想,接口的实现由 provider 实现,provider 只用在提交的 jar 包里的 META-INF/services 下根据平台定义的接口新建文件,并添加进相应的实现类内容就好。

使用 jar 包通过 spi动态实现接口功能

新增 jar包,打包后加载到其他项目运行。

public interface Search {
    List<String> searchDoc(String keyword);
}
//-
public class DefaultSearch implements Search{
    @Override
    public List<String> searchDoc(String keyword) {
        System.out.println("default search");
        return null;
    }
}
//-
public class MainApplicaction {
    public static void main(String[] args) {
        ServiceLoader<Search> s = ServiceLoader.load(Search.class);
        Iterator<Search> iterator = s.iterator();
        while (iterator.hasNext()) {
            Search search =  iterator.next();
            search.searchDoc("hello world");
        }
        System.out.println(">>>> jar main end");
    }
}

然后 mvn install到本地,把 jar包导入到其他项目

package com.example.spi;
import com.example.MainApplicaction;
import com.example.Search;
import java.util.List;
public class SpiApplication {
    public static class FileSearch implements Search {
        @Override
        public List<String> searchDoc(String keyword) {
            System.out.println("文件搜索 "+keyword);
            return null;
        }
    }
    public static class DatabaseSearch implements Search{
        @Override
        public List<String> searchDoc(String keyword) {
            System.out.println("数据搜索 "+keyword);
            return null;
        }
    }
    public static class RpcSearch implements Search{
        @Override
        public List<String> searchDoc(String keyword) {
            System.out.println("rpc搜索 "+keyword);
            return null;
        }
    }
    public static void main(String[] args) {
        MainApplicaction.main(new String[0]);
    }
}

运行结果

文件搜索 hello world
数据搜索 hello world
rpc搜索 hello world
default search
>>>> jar main end

由此可以看到本项目的 META-INF/services的加载顺序在 jar包前面。

相关文章
|
22天前
|
XML 设计模式 Java
依赖注入艺术:探索Spring如何实现松耦合的神奇
依赖注入艺术:探索Spring如何实现松耦合的神奇
39 0
依赖注入艺术:探索Spring如何实现松耦合的神奇
|
7月前
|
Dubbo Java 应用服务中间件
阿里一面:说一说Java、Spring、Dubbo三者SPI机制的原理和区别
大家好,我是三友~~ 今天来跟大家聊一聊Java、Spring、Dubbo三者SPI机制的原理和区别。 其实我之前写过一篇类似的文章,但是这篇文章主要是剖析dubbo的SPI机制的源码,中间只是简单地介绍了一下Java、Spring的SPI机制,并没有进行深入,所以本篇就来深入聊一聊这三者的原理和区别。
|
8月前
|
Dubbo Java 应用服务中间件
JDK SPI、Spring SPI、Dubbo SPI三种机制的细节与演化
Java SPI(Service Provider Interface)是JDK提供的一种服务发现机制,用于在运行时动态加载和扩展应用程序中的服务提供者。
187 0
|
8月前
|
Java 数据库连接 API
你知道Spring Boot插件开发模式思想—SPI机制是什么吗?
`SPI`全称`Service Provider Interface`,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。本质是**将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类**。这样可以在运行时,动态为接口替换实现类。通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类,进而实现可插拔,解耦。
23009 4
|
9月前
|
Java 数据库连接 数据库
深入浅出:SPI 机制在 JDK 与 Spring Boot 中的应用
本文分享自华为云社区《Spring 高手之路 14—— 深入浅出:SPI 机制在 JDK 与 Spring Boot 中的应用》,作者:砖业洋__ 。 Spring Boot 不仅是简化 Spring 应用开发的工具,它还融合了许多先进的机制。本文深入探讨了 Spring Boot 中与 Java 的标准 SPI 相似的机制,揭示了它的工作原理、应用场景及与标准 SPI 的异同。文章通过实际代码示例为你展示了如何在 Spring Boot 中使用这一机制,并以形象的比喻帮助你理解其背后的思想
374 0
|
9月前
|
Java 数据库连接 数据库
Spring高手之路14——深入浅出:SPI机制在JDK与Spring Boot中的应用
Spring Boot不仅是简化Spring应用开发的工具,它还融合了许多先进的机制。本文深入探讨了Spring Boot中与Java的标准SPI相似的机制,揭示了它的工作原理、应用场景及与标准SPI的异同。文章通过实际代码示例为你展示了如何在Spring Boot中使用这一机制,并以形象的比喻帮助你理解其背后的思想。
411 0
Spring高手之路14——深入浅出:SPI机制在JDK与Spring Boot中的应用
|
10月前
|
Java 测试技术 Spring
探究Spring Boot中的IoC容器:实现松耦合的依赖管理
在现代的软件开发中,松耦合和可维护性是极其重要的设计原则。Spring Boot作为一款流行的Java框架,借助于控制反转(IoC)的机制,实现了高度松耦合的组件之间的依赖管理,提高了代码的可维护性和可测试性。本文将深入介绍Spring Boot中的IoC容器,探讨IoC的基本概念、Spring Boot的IoC支持,以及如何在实际应用中利用IoC构建强大的应用。
124 0
|
消息中间件 JavaScript 小程序
深入剖析 Spring Boot 的 SPI 机制
深入剖析 Spring Boot 的 SPI 机制
|
XML 消息中间件 Java
Spring基础篇:动手感受一下松耦合
从思想上丝滑过渡到Spring的核心:如何让程序解耦。结合UML图介绍工厂+反射的方式创建Bean工厂。
109 0
|
Dubbo Java 应用服务中间件
【视频讲解配套PPT】Java SPI | Dubbo SPI |Spring SPI有什么区别
SPI(Service Provider Interface)是一种服务发现机制,它通过在类路径下的META-INF/services目录下的配置文件来发现服务实现类,实现了面向接口编程的扩展性。
233 0
【视频讲解配套PPT】Java SPI | Dubbo SPI |Spring SPI有什么区别