java的spi(Service Provider Interface)机制及源码(java8)
1.什么是java的spi
spi 全称为 service provider interface 即 服务提供接口,用来作为服务的扩展发现。在运行时动态添加接口的实现,是对接口的实现类的创建管理。
2.运用场景
3.如何使用
java 自带的spi
private static final String PREFIX = "META-INF/services/";
//指定类加载器
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(service, loader);
}
//使用当前线程的类加载器
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
} //使用extension class loader
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
ClassLoader prev = null;
while (cl != null) {
prev = cl;
cl = cl.getParent();
}
return ServiceLoader.load(service, prev);
}
3. 调用ServiceLoader.load()方法后会new 一个 ServiceLoader<>(Class service, loader);
private ServiceLoader(Class<S> svc, ClassLoader cl) {
// 这里的service 是对应的接口
service = Objects.requireNonNull(svc, "Service interface cannot be null");
// 类加载器
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
//获取当前的AccessControlContext 默认为空
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
这里的acc 是 java的安全管理器
// The access control context taken when the ServiceLoader is created
private final AccessControlContext acc;
java.lang.System类中 private static volatile SecurityManager security = null; public static SecurityManager getSecurityManager() {
return security;
}
4.接着调用reload方法
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
providers 同lookupInterator
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>(); // The current lazy-lookup iterator
private LazyIterator lookupIterator;
5.new 一个内部类 懒加载类LazyInterator
private class LazyIterator
implements Iterator<S>
{ Class<S> service;
ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null; private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
} private boolean hasNextService() {
if (nextName != null) {
return true;
}
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);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
} private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
} public boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
} public S next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
} public void remove() {
throw new UnsupportedOperationException();
} }
6.使用迭代器Interator取出接口的实现对象
public Iterator<S> iterator() {
return new Iterator<S>() { Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator(); public boolean hasNext() {
if (knownProviders.hasNext())
return true;
return lookupIterator.hasNext();
} public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
} public void remove() {
throw new UnsupportedOperationException();
} };
}
java的spi(Service Provider Interface)机制及源码(java8)的更多相关文章
- SPI(Service Provider Interface)机制
JAVA SPI 约定如下:当服务的提供者提供了服务接口的一种实现之后,在jar包的META-INF/services/ 目录中同时创建一个以服务接口命名的文件,该文件中的内容就是实现该服务接口的具体 ...
- JAVA SPI(Service Provider Interface)原理、设计及源码解析(其一)
背景 团队内部轮流技术分享,其他人都是分享源码,我每次都是设计和架构,感觉自己太特立独行.这次我要合群点,分享点源码. 概念 Service Provider Interface:服务提供方接口.是一 ...
- Java SPI(Service Provider Interface)简介
SPI 简介 SPI 全称为(Service Provider Interface),是JDK内置的一种服务提供发现机制. 一个服务(Service)通常指的是已知的接口或者抽象类,服务提供方就是对这 ...
- Java SPI(Service Provider Interface)
SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制. 目前有不少框架用它来做服务的扩展发现, 简单来说,它就是一种动态替换发现的机制, 举个 ...
- SPI: Service Provider Interface
Service Provider Interface: JDK提供的一种服务发现的机制:主要是用于厂商实现JDK的只用. 比如说打印机,JDK提供了一个驱动接口com.printl.printerDr ...
- Java中的SPI(Service Provider Interface)
转自:http://singleant.iteye.com/blog/1497259 最近看到公司的一些框架和之前看到的开源的一些框架的一些服务发现和接入都采用了java的spi机制. 所以简单的总结 ...
- SPI(Service Provider Interface)--通过接口获取服务
spi 现在已有实现 jdk 提供实现 dubbo里的spi实现 一.jdk实现 配置 定义接口 定义实现类 配置资源文件 classpath下创建(META-INF/services/接口全面:ME ...
- Service Provider Interface
@(Java)[SPI] Service Provider Interface API的一种设计方法,一般用于一些服务提供给第三方实现或者扩展,可以增强框架的扩展或者替换一些组件. 结构 Servic ...
- 【Java实战】源码解析Java SPI(Service Provider Interface )机制原理
一.背景知识 在阅读开源框架源码时,发现许多框架都支持SPI(Service Provider Interface ),前面有篇文章JDBC对Driver的加载时应用了SPI,参考[Hibernate ...
随机推荐
- Linux压缩、解压
gzip压缩: 归档,压缩,yourFloder文件夹生成yourName.tar.gz: - tar -zcvf yourName.tar.gz yourFloder 解压yourName.tar. ...
- ios UIWebView加载HTMLStr图文,关于图片宽高设置,webView内容实际高度的踩坑问题
一.关于UIWebView 与 WKWebView 选取问题 从发布时间看: 2008年7月11日,在新一代iPhone3G正式发售当天,iPhone OS 2.0(iOS 2.0)推出,这时候就有U ...
- [CQOI2015]网络吞吐量(网络流+SPFA)
[CQOI2015]网络吞吐量 题目描述 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器.为了使数据包最快的到达目的 ...
- 【学习】004 java并发包
并发包[jdk1.7] 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不 ...
- 命令行界面CLI
1.hive -e --执行一个或多个查询 hive -e "select * from student limit 3" 2. hive -e > 将临时查询保 ...
- luogu P3411 序列变换
链接 P3411 序列变换 如果要最小化答案,那么就最大化不移动的数. 那么不移动的子序列一定是最后答案的一段连续区间,而移动的数我们是一定有办法把他们还原的. 设\(f_{i}\)表示\(i\)点的 ...
- bzoj3589 动态树 树链剖分+容斥
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3589 题解 事件 \(0\) 不需要说,直接做就可以了. 事件 \(1\) 的话,考虑如果直接 ...
- 远程连接Linux相关操作
1.远程连接的步骤 编译网卡配置文件,修改onboot参数 vi /etc/sysconfig/network-scripts/ifcfg-ens33进入命令之后将onboot改成onboot=yes ...
- matplotlib--直线和点
直线和点: import matplotlib.pyplot as plt import numpy as np x=np.linspace(-10,10,10) y=x**2 h=plt.plot( ...
- mysql中 key 、primary key 、unique key 和 index 有什么不同
mysql中 key .primary key .unique key 和 index 有什么不同 key 是数据库的物理结构,它包含两层意义和作用, 一是约束(偏重于约束和规范数据库的结构完整性), ...