首页 > 编程语言 >Java SPI 代码示例

Java SPI 代码示例

时间:2024-02-04 18:34:45浏览次数:30  
标签:LoggerB Java ServiceLoader 示例 public SPI LoggerA LoggerForSpiTest String

Java Service Provider Interface 是JDK自带的服务提供者接口又叫服务发现机制更是一种面向接口的设计思想。即JDK本身提供接口类, 第三方实现其接口,并作为jar包或其他方式注入到其中, 在运行时会被JDK ServiceLoader 发现并加载,自动调用实现类的方法。

1. 在本地测试SPI机制

本人使用类似日志记录组件, 项目一提供接口,由第三方(项目二)提供自定义日志实现类。tips: 一般影响力大的机构或组织才可以定义SPI接口 比如Java , SLF4J, Spring ~

JDK: Java21

image

  1. 在原有项目一(sample)创建测试类,以及接口文件
  2. 新建项目二(spitest) 提供多个实现类
  3. 最重要的:在spitestMETA-INF/services 文件夹下增加配置文件, 命名为 sample中接口类的全路径限定名
  4. 执行测试类,查看结果

1.1 项目一增加测试类及接口

import java.util.ServiceLoader;

public class JdkSpi {
    public static void main(String[] args) {
        ServiceLoader<LoggerForSpiTest> spiTests = ServiceLoader.load(LoggerForSpiTest.class);
        spiTests.forEach( logger -> System.out.println(logger.log("hello ")));
    }
}

接口:

public interface LoggerForSpiTest {
    String log (String msg);
}

2.1 项目二 实现类

由于实现类需要引入此接口类LoggerForSpiTest, 因此打包时候可以去除掉接口类即可

实现类LoggerA

import com.jay.base.LoggerForSpiTest;

public class LoggerA implements LoggerForSpiTest {
    @Override
    public String log(String msg) {
        return msg + "i am LoggerA";
    }
}

实现类LoggerB

import com.jay.base.LoggerForSpiTest;

public class LoggerB implements LoggerForSpiTest {
    @Override
    public String log(String msg) {
        return msg + "i am LoggerB";
    }
}

3.1 项目二中添加配置文件

image

com.jay.spi.LoggerA
com.jay.spi.LoggerB

其中内容是 实现类的路径限定名, 由于我实现了两个Logger为了区分效果,实际可能只需要一个,例如mysql jdbc connector jar包中
image
其中jdk 提供了Driver接口类, 让第三方如 Mysql, Oracle, SqlServer 等实现其厂家自己的实现类.

4.1 打包项目二spitest为jar,导入到项目一sample

打包只用包含 spitest compile output即可,即 只需要spitest中自己写的代码的编译文件打成jar
image
导入成功后,打开jar只能看到三个文件即 LoggerA, LoggerB, 以及META-INF/services里面的配置文件
image

4.2 运行测试类JdkSpi.java

输出结果为:

hello i am LoggerA
hello i am LoggerB

2. FYI.

类似于我们使用的日志打印组件,代码会在ServiceLoader.load(LoggerForSpiTest.class) 方法中构造ServiceLoader对象, 而其是继承了Iterable接口,在代码spiTests.forEach( logger -> System.out.println(logger.log("hello "))); 中迭代去使用的时候去加载META-INF/services下的所有实现类 LoggerA, LoggerB至此本文不再扩展,会再次以新文章介绍。
`

 @CallerSensitive
    public static <S> ServiceLoader<S> load(Class<S> service) {  
        ClassLoader cl = Thread.currentThread().getContextClassLoader();  //获取当前类加载器
        return new ServiceLoader<>(Reflection.getCallerClass(), service, cl); // 构造ServiceLoader(调用类, 接口类, 类加载器)
    }

关于Reflection.getCallerClass()看到源码注释是会跳过所有反射的过程直达调用的地方,类似编码过程中发现报错我们可以通过一些IDE看到stack info 并看到最初调用的地方排查问题。由于本文不介绍反射,所以不宜继续扩展。

标签:LoggerB,Java,ServiceLoader,示例,public,SPI,LoggerA,LoggerForSpiTest,String
From: https://www.cnblogs.com/jaycezheng/p/18006761

相关文章

  • [java] Tomcat 启动失败 Error: error while reading constant pool for .class: unex
    表现公司服务器今天启动tomcat失败,看catalina.out文件里面报错java.lang.ClassFormatError:Unknownconstanttag101inclassfilecn/world/data尝试解决查了一下,网上一般认为是字符串的问题,但是代码文件目标行是英文字符串,只是简单的println了字符串,应该不会有问题。尤......
  • Caused by: java.lang.IllegalStateException: A unix domain socket connection requ
    Causedby:java.lang.IllegalStateException:Aunixdomainsocketconnectionrequiresepollorkqueueandneitherisavailable出现这个错误,首先确保自己的操作系统是否支持epoll,或者kqueue。如果支持。请导入netty的大库,lettuce中好像缺失了一部分,我怀疑是这是怀疑,......
  • Java之解决跨域
    跨域问题是浏览器为了保护用户的信息安全,实施了同源策略(Same-OriginPolicy),即只允许页面请求同源(相同协议、域名和端口)的资源,当JavaScript发起的请求跨越了同源策略,即请求的目标与当前页面的域名、端口、协议不一致时,浏览器会阻止请求的发送或接收。......
  • Java原子性、可见性、有序性的解析
    一、原子性原子性指操作在CPU执行的过程中,不可中断,也不可在中途切换,要么执行完成要么不执行。packagelearn;/***@authorqx*@date2024/1/5*@des*/publicclassThreadAtomicityTest{privateintstep;publicintgetStep(){returnstep;......
  • 【JAVA】Java 使用 XPath表达式定位节点读取自定义XML方法
    *加载配置文件节点*@paramattributeValue节点属性值*@paramareaCode节点属性值*/publicstaticMap<String,String>getConfigXml(StringattributeValue,StringareaCode){StringfilePath="config.xml";Map<St......
  • 深入浅出Java多线程(七):重排序与Happens-Before
    引言大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第七篇内容:重排序与Happens-Before。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!!在上一篇文章中,我们简单提了一下重排序与Happens-Before。在这篇文章中我们将深入讲解一下重排序与Happens-Before,然......
  • java代码实现自动生成数据库表er图
    最近有同事看到字节跳动产品设计文档里有数据库表er图。就想问问又没有现成的工具也给直接生成一个er图,经查找验证发现并没有。因为现在表关系都是用的逻辑外键而非物理外键约束的,所以像navicat等工具就算生成了也没有描述关系的连接线。那么为了满足需求,这边就略微出手写了个代码......
  • Java AQS
    AQS介绍AQS的全称为 AbstractQueuedSynchronizer ,翻译过来的意思就是抽象队列同步器。这个类在 java.util.concurrent.locks 包下面。AQS就是一个抽象类,主要用来构建锁和同步器。publicabstractclassAbstractQueuedSynchronizerextendsAbstractOwnableSynchronizer......
  • Java压缩文件为ZIP并加密
    1:引入jar包<dependency><groupId>net.lingala.zip4j</groupId><artifactId>zip4j</artifactId><version>1.3.1</version></dependency> 2:单文件压缩 importnet.lingala.z......
  • javaee平台技术
    3.spring和springboot3.3spring容器BeanFactory:创建Bean对象以及管理Bean对象。 ApplicationContext:BeanFactory的子接口,继承了其所有能力外,还追加了其他功能。  控制反转实现机制:将对象间的依赖交给容器去处理,利用set或构造函数的方法把依赖注射进来,告诉其关联关系,主......