JAVA SPI 简介
SPI 是 Java 提供的一种服务加载方式,全名为 Service Provider Interface。根据 Java 的 SPI 规范,我们可以定义一个服务接口,具体的实现由对应的实现者去提供,即服务提供者。然后在使用的时候再根据 SPI 的规范去获取对应的服务提供者的服务实现。通过 SPI 服务加载机制进行服务的注册和发现,可以有效的避免在代码中将具体的服务提供者写死。从而可以基于接口编程,实现模块间的解耦。
SPI 机制的约定
1 在 META-INF/services/ 目录中创建以接口全限定名命名的文件,该文件内容为API具体实现类的全限定名
2 使用 ServiceLoader 类动态加载 META-INF 中的实现类
3 如 SPI 的实现类为 Jar 则需要放在主程序 ClassPath 中
4 API 具体实现类必须有一个不带参数的构造方法
SPI 应用场景举例
JDBC
jdbc4.0以前, 开发人员还需要基于Class.forName("xxx")的方式来装载驱动,jdbc4也基于spi的机制来发现驱动提供商了,可以通过METAINF/services/java.sql.Driver文件里指定实现类的方式来暴露驱动提供者.
COMMON-LOGGING
apache最早提供的日志的门面接口。只有接口,没有实现。具体方案由各提供商实现, 发现日志提供商是通过扫描METAINF/services/org.apache.commons.logging.LogFactory配置文件,通过读取该文件的内容找到日志提工商实现类。只要我们的日志实现里包含了这个文件,并在文件里制定 LogFactory工厂接口的实现类即可。
SPI 机制代码示例
接口 People.java
package org.louis.spi.test; public interface People { public String speak(); }
实现类 Chinese.java
package org.louis.spi.test; public class Chinese implements People{ public String speak() { return "Chinese speak Chinese."; } }
实现类 American.java
package org.louis.spi.test; public class American implements People{ public String speak() { return "American speak English."; } }
创建一个文件,放置到 META-INF/Services 目录:
文件名:org.louis.spi.test.People
文件内容:
org.louis.spi.test.Chinese org.louis.spi.test.American
新建一个测试工程,引入以上代码生成的Jar包
测试类SpiTest.java
package org.louis.test; import java.util.Iterator; import java.util.ServiceLoader; import org.louis.spi.test.People; import org.louis.spi.test.Chinese; import org.louis.spi.test.American; public class SpiTest { public static void main(String[] args) { ServiceLoader<People> peoples = ServiceLoader.load(People.class); Iterator<IOperation> iterator = peoples.iterator(); while (iterator.hasNext()) { People people = iterator.next(); System.out.println(people.speak()); } } }
运行结果:
Chinese speak Chinese.
American speak English.
通过上面例子,我们看到,假如我要新加入一个韩国人的实现,那只需要新建一个新的工程,创建一个Koeran类实现People接口,并在自己工程 META-INF/Services 目录下放置一个配置文件指定Koeran实现类,将工程打成Jar包,就完成了一个新的服务实现的开发。
以上就是示例讲解JAVA SPI机制的详细内容,更多关于JAVA SPI机制的资料请关注小牛知识库其它相关文章!
本文向大家介绍linux epoll机制详解,包括了linux epoll机制详解的使用技巧和注意事项,需要的朋友参考一下 在linux 没有实现epoll事件驱动机制之前,我们一般选择用select或者poll等IO多路复用的方法来实现并发服务程序。在linux新的内核中,有了一种替换它的机制,就是epoll。 select()和poll() IO多路复用模型 select的缺点: 1.单个进程
本文向大家介绍python随机模块random使用方法详解,包括了python随机模块random使用方法详解的使用技巧和注意事项,需要的朋友参考一下 random随机模块包括返回随机数的函数,可以用于模拟或者任何产生随机输出的程序。 一.random模块常用函数介绍 random.random() — 生成一个从0.0(包含)到 1.0(不包含)之间的随机浮点数; random.uniform(
本文向大家介绍node.JS事件机制与events事件模块的使用方法详解,包括了node.JS事件机制与events事件模块的使用方法详解的使用技巧和注意事项,需要的朋友参考一下 node.JS事件机制说明 多数 Node.js 核心 API 都是采用惯用的异步事件驱动架构,其中某些类型的对象(称为触发器)会周期性地触发命名事件来调用函数对象(监听器)。例如,一个net.Server对象会在每次有
本文向大家介绍详解Android中AsyncTask机制,包括了详解Android中AsyncTask机制的使用技巧和注意事项,需要的朋友参考一下 在Android当中,提供了两种方式来解决线程直接的通信问题,一种是通过Handler的机制,还有一种就是今天要详细讲解的 AsyncTask 机制。 AsyncTask
本文向大家介绍Javascript 赋值机制详解,包括了Javascript 赋值机制详解的使用技巧和注意事项,需要的朋友参考一下 今天回答了一个关于 Javascript 的问题,涉及到了赋值问题,因此想把这个问题好好总结下。 执行上述代码后,变量 a 和 b 的值会发生改变吗? 原始值和引用值 在 之前的文章中介绍过原始值和引用值,原始值指的 Undefined, Null, Boolean,
本文向大家介绍python之import机制详解,包括了python之import机制详解的使用技巧和注意事项,需要的朋友参考一下 本文详述了Python的import机制,对于理解Python的运行机制很有帮助! 1.标准import: Python中所有加载到内存的模块都放在 sys.modules 。当 import 一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模