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的更多相关文章

  1. 【转】Java代码规范

    [转]Java代码规范 http://blog.csdn.net/huaishu/article/details/26725539

  2. 【深入】java 单例模式(转)

    [深入]java 单例模式 关于单例模式的文章,其实网上早就已经泛滥了.但一个小小的单例,里面却是有着许多的变化.网上的文章大多也是提到了其中的一个或几个点,很少有比较全面且脉络清晰的文章,于是,我便 ...

  3. 【转】Java HashMap 源码解析(好文章)

    ­ .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...

  4. 【解惑】Java动态绑定机制的内幕

    在Java方法调用的过程中,JVM是如何知道调用的是哪个类的方法源代码? 这里面到底有什么内幕呢? 这篇文章我们就将揭露JVM方法调用的静态(static binding) 和动态绑定机制(auto ...

  5. 【转】Java之 内存区域和GC机制

    转自:Leo Chin 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage ...

  6. 【三板斧】Java定位CPU使用高问题

    [三板斧]Java定位CPU使用高问题 1.TOP命令,查询消耗CPU高的进程号 PID,并记录下来,按下键盘"H"键,记录高消耗线程号,并将改线程号转换为十六进制 2.使用 js ...

  7. 【转】java.util.vector中的vector的详细用法

    [转]java.util.vector中的vector的详细用法 ArrayList会比Vector快,他是非同步的,如果设计涉及到多线程,还是用Vector比较好一些 import java.uti ...

  8. 【转】Java中equals和==的区别

    [转]Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boole ...

  9. 【转】JAVA的StringBuffer类

    [转]JAVA的StringBuffer类    StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和String不同,所以StringBu ...

  10. 【转】Java学习之Iterator(迭代器)的一般用法 (转)

    [转]Java学习之Iterator(迭代器)的一般用法 (转) 迭代器(Iterator) 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭 ...

随机推荐

  1. Android——监听事件总结

    各种监听事件 1.按钮 Button(1)点击监听 btn_1.setOnClickListener(new View.OnClickListener() { (2)长按监听 btn_1.setOnL ...

  2. 接口与virtual,override,new关键字

    一,类继承接口 1,首先我们定义一个简单的ITeacher接口,并定义一个Professor类继承它. public interface ITeacher { void Print(); } publ ...

  3. android开发(36) Android WebView背景设置为透明

    xml布局 <WebView android:id="@+id/wv_content" android:layout_width="match_parent&quo ...

  4. centos 7 升级/安装 git 2.7.3

      1.安装所需软件包 # yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel # yum instal ...

  5. DBExportDoc V1.0 For MySQL

    win7系统下或者64位系统下,安装完mysql-connector-odbc驱动后,直接进入:管理工具--数据源(ODBC),点击添加不显示该驱动,该问题解决如下:进入dos命令行,输入:C:\Us ...

  6. Java设计模式(2)单态模式(Singleton模式)

    定义:Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作. 还有,singleton能够被状态化 ...

  7. JAVA多线程笔试题

    一.题目内容 二.我的答案 利用了线程池.考虑了超时处理.不知道这样写是否还有其他问题,或者更好更优的解决方案? import java.util.*; import java.util.concur ...

  8. 在天河二号上对比Julia,Python和R语言

    Julia是一款高级高效为技术计算(technical computing)而设计的编程语言,其语法与其他计算环境类似.其为分布式计算和并行所设计,最知名的地方在于其接近C语言的高效率. 按开发者的话 ...

  9. Linux 安装 Oracle 11g R2

    一.安装环境 Linux服务器:Centos 6.4 64位 Oracle服务器:Oracle11gR2 64位 二.系统要求 Linux安装Oracle系统要求 系统要求 说明 内存 必须高于1G的 ...

  10. MD2关键桢动画3D模型加载.

    在看Cg教程中,看到关键桢插值来表示一个动画的物体,例如一个动物拥有站着,奔跑,下跪等动画序列,美工将这些特定的姿态称为一个关键桢.为什么要用关键桢这种来表示了,这个比较容易理解,我们知道我们看的一些 ...