ServiceLoader解读
SPI的全名为Service Provider Interface.普通开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。
简单来说就是通过配置文件指定接口的实现类。
当我们开发一套框架、一套机制、一个插件或一套API时候,如果需要第三方的服务支持,可以直接写死到代码里面,但这种方式耦合太强,不利于切换到其它服务,好的方法是写一个配置文件指定服务的实现方,幸运的是java的spi机制已经帮我们做好了,示例用法如下:
一个接口:
package com.service;
public interface IService {
String service();
}
两个实现类:
package com.service;
public class ServiceImplA implements IService {
public String service() {
return "invoke ServiceImplA";
}
}
package com.service;
public class ServiceImplB implements IService {
public String service() {
return "invoke ServiceImplB";
}
}
然后创建com.service.IService文件,写入如下内容:
com.service.ServiceImplA
com.service.ServiceImplB
其在Idea中的结构如下:

其中的mazhimazh-1.0-SNAPSHOT.jar是打包后的jar。然后放到Java项目的classpath中。
创建ServiceIterator,代码如下:
package com.test2;
import java.lang.reflect.Method;
import java.util.Iterator;
import com.service.IService;
/**
* Use a service loader appropriate for the platform to provide an
* iterator over annotations processors. If
* java.util.ServiceLoader is present use it, otherwise, use
* sun.misc.Service, otherwise fail if a loader is needed.
*/
public class ServiceIterator implements Iterator<IService> {
// The to-be-wrapped iterator.
private Iterator<?> iterator;
private Class<?> loaderClass;
private boolean jusl; // java util service loader
private Object loader;
ServiceIterator() {
ClassLoader classLoader = getClass().getClassLoader();
String loadMethodName;
try {
try {
loaderClass = Class.forName("java.util.ServiceLoader");
loadMethodName = "load";
jusl = true;
} catch (ClassNotFoundException cnfe) {
try {
loaderClass = Class.forName("sun.misc.Service");
loadMethodName = "providers";
jusl = false;
} catch (ClassNotFoundException cnfe2) {
// Fail softly if a loader is not actually needed.
return;
}
}
// java.util.ServiceLoader.load or sun.misc.Service.providers
// 获得对象所声明的公开方法,在这里获取ServiceLoader的load方法
// 该方法的第一个参数name是要获得方法的名字,第二个参数parameterTypes是按声明顺序标识该方法形参类型。
Method loadMethod = loaderClass.getMethod(loadMethodName,
Class.class,
ClassLoader.class);
// 调用方法 public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
Object result = loadMethod.invoke(null,
IService.class,
classLoader);
// For java.util.ServiceLoader, we have to call another
// method to get the iterator.
if (jusl) {
loader = result; // Store ServiceLoader to call reload later
Method m = loaderClass.getMethod("iterator");
result = m.invoke(result); // serviceLoader.iterator();
}
// The result should now be an iterator.
this.iterator = (Iterator<?>) result;
} catch (Throwable t) {
throw new Error(t);
}
}
public boolean hasNext() {
try {
return iterator.hasNext();
} catch (Throwable t) {
throw new Error(t);
}
}
public IService next() {
try {
return (IService)(iterator.next());
} catch (Throwable t) {
throw new Error(t);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
public void close() {
if (jusl) {
try {
// Call java.util.ServiceLoader.reload
Method reloadMethod = loaderClass.getMethod("reload");
reloadMethod.invoke(loader);
} catch(Exception e) {
; // Ignore problems during a call to reload.
}
}
}
}
然后调用,如下:
package com.test2;
import java.util.ServiceLoader;
import com.service.IService;
public class Test {
public static void main(String[] args) {
// 使用1
ServiceIterator s = new ServiceIterator();
while (s.hasNext()) {
IService x = s.next();
System.out.println(x.service());
}
// 使用2
ServiceLoader<IService> serviceLoader = ServiceLoader.load(IService.class);
for (IService service : serviceLoader) {
System.out.println(service.service());
}
}
}
运行结果如下:
invoke ServiceImplA
invoke ServiceImplB
invoke ServiceImplA
invoke ServiceImplB
ServiceLoader解读的更多相关文章
- Java之ServiceLoader
转载请注明源出处:http://www.cnblogs.com/lighten/p/6946683.html 1.简介 JDK1.6之后,java.util包下多了一个类ServiceLoader,其 ...
- SDWebImage源码解读之SDWebImageDownloaderOperation
第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...
- SDWebImage源码解读 之 NSData+ImageContentType
第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...
- SDWebImage源码解读 之 UIImage+GIF
第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...
- SDWebImage源码解读 之 SDWebImageCompat
第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...
- SDWebImage源码解读_之SDWebImageDecoder
第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...
- SDWebImage源码解读之SDWebImageCache(上)
第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...
- SDWebImage源码解读之SDWebImageCache(下)
第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...
- AFNetworking 3.0 源码解读 总结(干货)(下)
承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...
随机推荐
- 团队博客第三周(Running Duck队)
代码链接:Tetris 码云链接 一.需求&原型改进 1.原型改进 汉字方块每次可生成一个并逐渐下落 可通过触摸左右下滑动实现方块的左右移动和快速下滑 左上角按钮可对汉字进行暂时保存和替换 右 ...
- Android工具类整合
Android-JSONUtil工具类 常用的Json工具类,包含Json转换成实体.实体转json字符串.list集合转换成json.数组转换成json public class JSONUtil ...
- Linux Socket - UDP链接包
LINUX UDP SOCKET 01 UDP号绑定会报错吗? 会的,提示Address is using,本地的没有区别 UDP不需要发起链接,不知道是不是连接成功 client的IP地址和端口号不 ...
- Hibernate 之核心接口
1.持久化和ORM 持久化是指把数据(内存中的对象)保存到可持久保存的存储设备中(如硬盘),主要应用于将内存中的数据存储到关系型数据库中,在三层结构中,持久层专注于实现系统的逻辑层面,将数据使用者与数 ...
- hadoop 2.7.3伪分布式安装
hadoop 2.7.3伪分布式安装 hadoop集群的伪分布式部署由于只需要一台服务器,在测试,开发过程中还是很方便实用的,有必要将搭建伪分布式的过程记录下来,好记性不如烂笔头. hadoop 2. ...
- h5页面宽度设置7.5rem
function ready() { var u = navigator.userAgent; var winW = document.documentElement.clientWidth; if ...
- c#设计模式之代理模式(Proxy Pattern)
引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...
- Webpack vs Rollup
本文由作者余伯贤授权网易云社区发布. 2017年4月份的时候,Facebook将React的构建工具换成了Rollup.很多人就有疑问了,Webpack不也是Facebook团队开发的吗,为什么不使用 ...
- Cookie背景了解
Cookie的复数形态是Cookies, 英文的意思是小甜饼,小饼干. 类型为小型文本文件, 指某些网站为了辨别用户身份储存在用户本地中断上的数据. 是前网景公司的员工 卢-蒙特利在1993年3月发明 ...
- django系列8.3.2--django中间件实现登录验证(2) 个人构想逻辑
middleware.py from django.utils.deprecation import MiddlewareMixin from django.shortcuts import rend ...