【java】 java SPI
SPI(Service provider interface)是旨在由第三方实现或扩展的API。它可以用于启用框架扩展和可替换组件。
服务是一组众所周知的接口或(通常是抽象的)类。服务提供者是服务的特定实现。提供程序中的类通常实现接口并对服务本身中定义的类进行子类化。服务提供程序可以以扩展的形式安装在Java平台的实现中,即,jar文件放置在任何通常的扩展目录中。提供者也可以通过将它们添加到应用程序的类路径或通过一些其他平台特定的手段。
在java中通过java.util.ServiceLoader 来实现。
先上代码:
Provider 可以为接口或者抽象类
package com.xwolf.spi.service;
/**
* Animal Provider
* @author xwolf
*
*/
public interface Animal { void eat(); void drink(); }
具体实现:
package com.xwolf.spi.service.impl;
import com.xwolf.spi.service.Animal;
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("Dog eat....");
}
@Override
public void drink() {
System.out.println("Dog drink....");
}
}
package com.xwolf.spi.service.impl;
import com.xwolf.spi.service.Animal;
public class Cat implements Animal {
@Override
public void eat() {
System.out.println("Cat eat....");
}
@Override
public void drink() {
System.out.println("Cat drink...");
}
}
将接口和具体实现放在文件META-INF/services中,文件名为全类名的Provider,内容为具体实现类的全类名。
测试方法:
package com.xwolf.spi.service;
import java.util.ServiceLoader;
public class ServiceLoaderTest {
public static void main(String[] args) {
//接口测试
ServiceLoader<Animal> loader=ServiceLoader.load(Animal.class);
for(Animal animal:loader){
animal.eat();
}
}
}
项目目录结构:

查看ServiceLoader部分源代码:

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
}
比较核心的代码就上边了,总之就是遍历的时候读取META-INF/services下所有为CLASS(本例子中的Animal)的全类名的文件内容,加载类。
【java】 java SPI的更多相关文章
- 【转】Java代码规范
[转]Java代码规范 http://blog.csdn.net/huaishu/article/details/26725539
- 【深入】java 单例模式(转)
[深入]java 单例模式 关于单例模式的文章,其实网上早就已经泛滥了.但一个小小的单例,里面却是有着许多的变化.网上的文章大多也是提到了其中的一个或几个点,很少有比较全面且脉络清晰的文章,于是,我便 ...
- 【转】Java HashMap 源码解析(好文章)
.fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...
- 【解惑】Java动态绑定机制的内幕
在Java方法调用的过程中,JVM是如何知道调用的是哪个类的方法源代码? 这里面到底有什么内幕呢? 这篇文章我们就将揭露JVM方法调用的静态(static binding) 和动态绑定机制(auto ...
- 【转】Java之 内存区域和GC机制
转自:Leo Chin 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage ...
- 【三板斧】Java定位CPU使用高问题
[三板斧]Java定位CPU使用高问题 1.TOP命令,查询消耗CPU高的进程号 PID,并记录下来,按下键盘"H"键,记录高消耗线程号,并将改线程号转换为十六进制 2.使用 js ...
- 【转】java.util.vector中的vector的详细用法
[转]java.util.vector中的vector的详细用法 ArrayList会比Vector快,他是非同步的,如果设计涉及到多线程,还是用Vector比较好一些 import java.uti ...
- 【转】Java中equals和==的区别
[转]Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boole ...
- 【转】JAVA的StringBuffer类
[转]JAVA的StringBuffer类 StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和String不同,所以StringBu ...
- 【转】Java学习之Iterator(迭代器)的一般用法 (转)
[转]Java学习之Iterator(迭代器)的一般用法 (转) 迭代器(Iterator) 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭 ...
随机推荐
- Maven MyEclipse创建web项目没有src/maim/java
转载:http://blog.csdn.net/nich002/article/details/43273219 maven项目 错误: 找不到或无法加载主类 分类: java2015-01-29 ...
- PHP——大话PHP设计模式——命名空间和类的自动载入
开发工具:phpstorm phpstudy 命名空间:声明当前文件 类的自动载入
- [转]Java中的POJO类
简单的Java对象(Plain Old Java Objects)实际就是普通JavaBeans,使用POJO名称是为了避免和EJB混淆起来, 而且简称比较直接. 其中有一些属性及其getter se ...
- Listener 监听Session内的对象
Listener用于监控Session内的对象,分别是HttpSessionBindingListener与HttpSessionActivationListener.它们的触发时机分别为: Http ...
- Overview & PPT 类型 & PPT 制作流程
PPT 策略 PPT 不能当讲稿 初次制作PPT的人常常把PPT当成大号讲稿,把演示时所有要说的话都变成文字做到PPT里,这 样的结果是观众很难记住PPT里到底讲了些什么需要我们帮助他们将文字尽可能转 ...
- 《jdk10》删除javah.exe文件,在Android studio编译jni,使用jdk10生成头文件
今天在用“死丢丢”编译so包的时候,只要一输入"javah -jni..."的命令就会一直提示 'javah'不是内部命令或外部命令,也不是可运行的程序或批处理文件 找了很久才发现 ...
- Linux 安装 Oracle 11g R2
一.安装环境 Linux服务器:Centos 6.4 64位 Oracle服务器:Oracle11gR2 64位 二.系统要求 Linux安装Oracle系统要求 系统要求 说明 内存 必须高于1G的 ...
- Windows错误码大全
0000 操作已成功完成.0001 错误的函数.0002 系统找不到指定的文件.0003 系统找不到指定的路径.0004 系统无法打开文件.0005 拒绝访问.0006 句柄无效.0007 存储区控制 ...
- Python——signal
该模块为在Python中使用信号处理句柄提供支持.下面是一些使用信号和他们的句柄时需要注意的事项: 除了信号 SIGCHLD 的句柄遵从底层的实现外,专门针对一个信号的句柄一旦设置,除非被明确地重置, ...
- chrome 下改动 agent 的方法
前言 这篇文章和 tiankonguse 的个人站点里的文章保持同步. 非常早之前,在 chrome 下改动 agent 的方法是使用 chrome 插件. 后来 chrome 的某一个版本号中自带这 ...