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 ...
随机推荐
- C++中的关键知识点(汇总)
1. class的virtual 与non-virtual的区别 (1)virtual 函数时动态绑定,而non-virtual是静态绑定,前者是多态效果. (2)多态类的析构函数应该为virtual ...
- day 20 02 模块的导入
day 20 02 模块的导入 1.模块:就是一个文件:放置一些通用的有独立功能程序或者函数.比如建立一个py文件,文件名为:demo,文件里面的内容:demo模块: print('嗨大米')def ...
- day15(生成器send方法,递归,匿名函数,内置函数)
一,复习 ''' 1.带参装饰器 - 自定义 | wraps def wrap(info) def outer1(func): from functools import wraps @wraps(f ...
- docker容器日志清理
1.先查看磁盘空间 df -h 2.找到容器的containerId-json.log文件,并清理(治标不治本,log迟早还会大的) 查看各个容器的log文件大小 find /var/lib/dock ...
- Linux中连接mysql执行sql文件
数据量小的时候可以把sql语句内容粘贴执行,但是文件很大的时候,这样执行效率很慢很慢,需要使用source执行sql文件 1.客户端连接mysql数据库 [root@iZbp1bb2egi7w0uey ...
- 日笔记--C# 从数据库取表格到DataGridView---json传输
只作为个人学习笔记. class OpData { // 创建一个和客户端通信的套接字 Socket socketwatch = null; //连接Access字符串 string strCon; ...
- yum 下载RPM包而不进行安装
yum命令本身就可以用来下载一个RPM包,标准的yum命令提供了--downloadonly(只下载)的选项来达到这个目的. $ sudo yum install --downloadonly < ...
- ADB 源码分析(一) ——ADB模块简述【转】
ADB源码分析(一)——ADB模块简述 1.Adb 源码路径(system/core/adb). 2.要想很快的了解一个模块的基本情况,最直接的就是查看该模块的Android.mk文件,下面就来看看a ...
- “全栈2019”Java第九十八章:局部内部类访问作用域成员详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- ava Maven项目之Nexus私服搭建和版本管理应用
目录: Nexus介绍 环境.软件准备 Nexus服务搭建 Java Maven项目版本管理应用 FAQ 1.Nexus介绍 Nexus是一个强大的Maven仓库管理器,它极大地简化了自己内部仓库的维 ...