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 ...
随机推荐
- POJ1679 The Unique MST 2017-04-15 23:34 29人阅读 评论(0) 收藏
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 29902 Accepted: 10697 ...
- 团体程序设计天梯赛L2-001 紧急救援 2017-03-22 17:25 93人阅读 评论(0) 收藏
L2-001. 紧急救援 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国 ...
- Android通过xml生成创建View的过程解析
Android的布局方式有两种,一种是通过xml布局,一种是通过java代码布局,两种布局方式各有各的好处,当然也可以相互混合使用.很多人都习惯用xml布局,那xml布局是如何转换成view的呢?本文 ...
- 关于fastjson的一个坑:输出json时,bean对象属性首字母默认被小写
fastjson 是一个性能很好的 Java 语言实现的 JSON 解析器和生成器,来自阿里巴巴. 主要特点: 快速FAST: 比其它任何基于Java的解析器和生成器更快,包括jackson 强大:支 ...
- 在Team Foundation Server (TFS)的代码库或配置库中查找文件或代码
[update 2017.2.11] 最新版本的TFS 2017已经增加了代码搜索功能,可以参考这个链接 https://blogs.msdn.microsoft.com/visualstudioal ...
- Buffer Pool--内存相关术语
虚拟地址空间(virtual address space): 供应用程序能够申请访问的最大地址空间,32位系统上为4GB,64位系统上是8TB,虚拟地址空间映射的数据不一定存放在物理内存中,还可能存放 ...
- tinymce与prism代码高亮实现及汉化的配置
简单介绍:TinyMCE是一个轻量级的基于浏览器的所见即所得编辑器,由JavaScript写成.它对IE6+和Firefox1.5+都有着非常良好的支持.功能方强大,并且功能配置灵活简单.另一特点是加 ...
- Dapper.Contrib.Extensions问题
Dapper.Contrib.Extensions问题 Dapper.Extension.1.0.0.1\lib\net45\Dapper.Extension.dll Dapper.Contrib.1 ...
- Python(序列化json,pickle,shelve)
序列化 参考:https://www.cnblogs.com/yuanchenqi/articles/5732581.html # dic = str({'1':'111'}) # # f = ope ...
- ROS(URDF机器人建模)
新建功能包mbot_description 在功能包下新建文件config,launch,meshes,urdf. 在launch文件夹下新建文件display_mbot_base_urdf.laun ...