Java-SPI机制

SPI基本概念

SPI(Service Provider Interface)是一种服务发现机制,为某个接口寻找服务实现的机制。这有点类似 IoC 的思想,将装配的控制权移交到了程序之外。SPI 将服务接口和具体的服务实现分离开来,将服务调用方和服务实现者解耦

SPI 和 API的区别

在这里插入图片描述
API:实现方提供了接口和实现,调用方调用实现方的接口进行使用,这就是 API ,即接口和实现都是在实现方
SPI:接口存在于调用方这边时,就是 SPI ,由接口调用方确定接口规则,然后由不同的厂商去根据这个规则对这个接口进行实现,从而提供服务

实例

SLF4J (Simple Logging Facade for Java)是 Java 的一个日志门面(接口),其具体实现有几种,比如:Logback、Log4j、Log4j2 等等,而且还可以切换,在切换日志具体实现的时候我们是不需要更改项目代码的,只需要在 Maven 依赖里面修改一些 pom 依赖就好了
在这里插入图片描述
简单的代码示例
1)定义接口
新建logger接口

public interface Logger {
    void info(String msg);
    void debug(String msg);
}

2)LoggerService
主要是为服务使用者提供特定接口,它不实现接口,但其可以拥有具体的接口实现方法
它能提供功能的核心原因是ServiceLoader 代码中会涉及ServiceLoader的使用,可以先看。这里只需要知道ServiceLoader可以帮服务提供者(LoggerSerive)做以下事情:
1.LoggerService将服务接口注册到/META-INF/services,ServiceLoader通过 URL 工具类从该目录下面找到对应的文件
2.读取这个文件的名称找到对应的待实现的接口
3.通过 InputStream 流将文件里面的具体实现类的全类名读取出来
4.根据获取到的全类名,先判断跟 spi 接口是否为同一类型,如果是的,那么就通过反射的机制构造对应的实例对象,将构造出来的实例对象添加到服务提供者的Providers 的列表中

public class LoggerService {
    private static final LoggerService SERVICE = new LoggerService();

    private final Logger logger;
	//实现Logger接口的方法类
    private final List<Logger> loggerList;
    private LoggerService() {
        ServiceLoader<Logger> loader = ServiceLoader.load(Logger.class);
        List<Logger> list = new ArrayList<>();
        for (Logger log : loader) {
            list.add(log);
        }
        // LoggerList 是所有 ServiceProvider
        loggerList = list;
        if (!list.isEmpty()) {
            // Logger 只取一个
            logger = list.get(0);
        } else {
            logger = null;
        }
    }

    public static LoggerService getService() {
        return SERVICE;
    }

    public void info(String msg) {
        if (logger == null) {
            System.out.println("info 中没有发现 Logger 服务提供者");
        } else {
            logger.info(msg);
        }
    }
    public void debug(String msg) {
        if (loggerList.isEmpty()) {
            System.out.println("debug 中没有发现 Logger 服务提供者");
        }
        loggerList.forEach(log -> log.debug(msg));
    }
}

此时并没有为 Logger 接口提供任何的实现,所以输出结果中没有按照预期打印相应的结果。

新建一个项目具体实现Logger接口

Logback

实现logger接口

public class Logback implements Logger {
    @Override
    public void info(String s) {
        System.out.println("Logback info 打印日志:" + s);
    }

    @Override
    public void debug(String s) {
        System.out.println("Logback debug 打印日志:" + s);
    }
}

在 src 目录下新建 META-INF/services 文件夹,然后新建文件 xxxx.spi.Logger (SPI 的全类名 即接口的全类名),文件里面的内容是:xxxx.spi.service.Logback (Logback 的全类名,即 SPI 的实现类的包名 + 类名)

测试
public class TestJavaSPI {
    public static void main(String[] args) {
    	//loggerService中可以加载具体的实现类
        LoggerService loggerService = LoggerService.getService();
        loggerService.info("你好");
        loggerService.debug("测试Java SPI 机制");
    }
}

ServiceLoader(源码部分阅读待补充)

接下来,详细看看ServiceLoader
这个类是一个 final 类型的,所以是不可被继承修改,同时它实现了 Iterable 接口。之所以实现了迭代器,是为了方便后续我们能够通过迭代的方式得到对应的服务实现。

public final class ServiceLoader<S> implements Iterable<S>{ xxx...}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/342958.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

理解反向代理

反向代理是一个不可或缺的组件。 它在客户端和服务器之间充当中介&#xff0c;提高了安全性、负载平衡和应用性能。 一、反向代理简介 反向代理是一种服务器&#xff0c;它位于客户端和后端服务器之间。与常见的&#xff08;正向&#xff09;代理不同&#xff0c;反向代理代表…

爬取A站视频,涉及m3u8格式的处理

一、抓包分析 1.进入A站进行抓包分析 进入一个页面&#xff0c;右点击鼠标按钮&#xff0c;点击检查 接着点击network&#xff0c;点击Fetxh/XHR,然后刷新网页&#xff0c;得到下面的页面 发现其中有许多d595开头的文件&#xff0c;它们是ts文件&#xff0c;点击其中一个。在…

v38.Switch语句

1.Switch语句可以替代if-else语句 2.具体使用 Switch&#xff08;expression&#xff09; &#xff5b; case label&#xff1a;...... &#xff5d; ①将x与case后的label 进行比较&#xff1b; ②注意后面有冒号&#xff1b; ③从上往下开始检查case&#xff1b; ④如果…

Transform模型详解

Transformer模型详解 Encoder与Decoder输入单词Embedding位置 Embedding 自注意力机制Self-Attention 结构Self-Attention 的输出Multi-Head Attention Encoder 结构Add & NormFeed Forward组成 Encoder Decoder结构Decoder第一个 Multi-Head AttentionDecoder第二个 Multi…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-9 HTML5 表单验证

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>HTML5 表单验证</title> </head><body> <form action"#" method"get">请输入您的邮箱:<input type"email&q…

【AI的未来 - AI Agent系列】【MetaGPT】6. 用ActionNode重写技术文档助手

文章目录 0. 前置推荐阅读1. 重写WriteDirectory Action1.1 实现WriteDirectory的ActionNode&#xff1a;DIRECTORY_WRITE1.2 将 DIRECTORY_WRITE 包进 WriteDirectory中 2. 重写WriteContent Action2.1 思考重写方案2.2 实现WriteContent的ActionNode2.3 改写WriteContent Act…

记录一下对集合排序,处理属性为空且参与排序方法

一、需求 实际项目中经常存在对集合某个或多个属性进行排序&#xff0c;例如根据姓名排序&#xff0c;根据金额排序&#xff1b;或者多个字段排序&#xff0c;例如姓名首字母升序金额降序两个字段排序等等。 但是有时候姓名或金额会为空&#xff0c;之前我们排序的时候需要拿出…

(Bean工厂的后处理器入门)学习Spring的第七天

一 . Bean工厂的后处理器入门 : 直接上图 BeanDefinitionRegistyPostProcessor 为 BeanFactoryProcessor的子接口 , 前者先执行(图里只有Bean工厂的后处理器第一个类型) 如下图 : 这两个接口可改变两个Map(BeanDefinitionMap , singletonObject)里的信息 (黑马只讲了BeanFact…

linux LPT和COM回路测试(基于python+Qt+C++)

软件UI: 回路治具&#xff08;COMLPT&#xff09;&#xff1a; lpt_test.cpp&#xff08;c 源代码&#xff09;&#xff1a; #include <iostream> #include <fstream> #include <sstream> #include <unistd.h> #include <fcntl.h> #include <…

SCDN高防如何保护你的服务器

随着互联网的发展&#xff0c;如今的网络世界&#xff0c;虽说给我们的衣食住行带来了非常大的便利&#xff0c;但同时它存在着各种各样的威胁。比如我们的网站&#xff0c;如果不做任何保护措施的话&#xff0c;就很容易被DDoS、CC等攻击堵塞网络、窃取目标系统的信息&#xf…

惬意上手Python —— 装饰器和内置函数

1. Python装饰器 Python中的装饰器是一种特殊类型的函数&#xff0c;它允许用户在不修改原函数代码的情况下&#xff0c;增加或修改函数的行为。 具体来说,装饰器的工作原理基于Python的函数也是对象这一事实&#xff0c;可以被赋值给变量、作为参数传递给其他函数或者作为其他…

【易经】-- 风水基础

目录 一、基础概念 1、五行 2、十天干 3、十二地支 4、八卦 4.1 伏羲八卦次序图 4.2 八卦对应自然界的基本事物 4.3 八卦及所代表的意像 ​编辑 5、生辰八字 5.1 定义 5.2 换算方法 5.3 举例 5.4 八字排盘示例 5.5 算法实现 二、举例 1、计算某年的生肖和年的属…

【nginx实战】nginx正向代理、反向代理、由反向代理实现的负载均衡、故障转移详解

文章目录 一. 正向代理与反向代理的概念二. Nginx服务器的正向代理服务1. Nginx服务器正向代理服务的配置的3个指令1.1. resolver指令1.2. resolver_timeout指令1.3. proxy_pass指令 2. Nginx服务器正向代理服务的使用 三. Nginx服务器的反向代理服务1. 反向代理的基本指令1.1.…

高数总结(1

目录 1.总结&#xff1a;小结&#xff1a; 1.总结&#xff1a; 小结&#xff1a; 关注我给大家分享更多有趣的知识&#xff0c;以下是个人公众号&#xff0c;提供 ||代码兼职|| ||代码问题求解|| 由于本号流量还不足以发表推广&#xff0c;搜我的公众号即可&#xff1a;

基于51单片机的超声波物位测量系统[proteus仿真]

基于51单片机的超声波物位测量系统[proteus仿真] 超声波检测系统这个题目算是课程设计和毕业设计中常见的题目了&#xff0c;本期是一个103基于51单片机的超声波物位测量系统 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】&#xff0c;赞赏任意文章 2&#xf…

Redis 笔记二

概览 1.高并发秒杀问题及可能出现的bug 2.秒杀场景JVM级别锁和分布式锁 3.大厂分布式锁Redisson框架 4.从Redisson源码剖析lua解决锁原子性问题 5.从Redisson源码剖析经典锁续命问题 6.Redis主从架构锁失效如何解决 7.Redlock分布式锁高并发下可能存在的问题 8.双十一大促如何将…

【学习】FPN特征金字塔

论文&#xff1a;Feature Pyramid Networks for Object Detection &#xff08;CVPR 2016) 参考blog&#xff1a;https://blog.csdn.net/weixin_55073640/article/details/122627966 参考视频讲解&#xff1a;添加链接描述 卷积网络中&#xff0c;深层网络容易响应语义特征&am…

【C++】list容器功能模拟实现

介绍 上一次介绍了list队容器的迭代器模拟&#xff0c;这次模拟实现list的简单功能&#xff0c;尤其要注意构造函数、析构函数、以及赋值运算符重载的实现。 list容器需要接纳所有类型的数据&#xff0c;因此&#xff0c;结构设置与迭代器设置同理&#xff0c;需要引入结点&…

Dirichlet Process 3

本节来介绍如何构造G&#xff0c;这里使用Stick-breaking construction算法 如下图H是关于的分布 对于G&#xff0c;这里面有2个变量&#xff0c;一个是&#xff0c;即采样的位置&#xff0c;一个是&#xff0c;即的权重 每次采样一次称为一个item 第一次采样 ,, 第二次采样…

c++的命名空间

命名空间 一.c的关键字二.命名空间2.1 命名空间定义2.1 命名空间的使用2.1.1加命名空间名称及作用域限定符2.1.2使用using将命名空间中某个成员引入 三.标准命名空间std 一.c的关键字 c中一共有63个关键字 关键字11111asmdoifreturntrycontinueautodoubleinlineshorttypedeff…