Java基础系列-SPI你认识吗
原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755313.html
一、SPI是什么
SPI是相对API而言的。
API指的是应用对服务调用方提供的接口,用于提供某种服务、功能,面向的是服务调用方。
SPI指的是应用对服务实现方提供的接口,用于实现某种服务、功能,面向的是服务实现方
二、SPI的使用
2.1 第一步:创建服务接口
package com.dh.spi;
public interface Fruit {
String getName();
}
2.2 第二步:创建多个服务实现
package com.dh.spi;
public class Apple implements Fruit {
@Override
public String getName() {
return "apple";
}
}
package com.dh.spi;
public class Banana implements Fruit {
@Override
public String getName() {
return "Banana";
}
}
这里的两个服务实现类,针对的是两个服务实现方,一方实现了Apple,另一方实现了Banana。
2.3 第三步:创建配置文件
在resource下创建/META-INF/services目录,在services目录下创建以服务接口全限定名为名称的文件:com.dh.spi.Fruit
文件内容为,当前服务实现的服务实现者类的全限定名
com.dh.spi.Apple
2.4 第四步:创建测试类
public class Test {
public static void main(String[] args) {
ServiceLoader<Fruit> s = ServiceLoader.load(Fruit.class);
Iterator<Fruit> it = s.iterator();
while(it.hasNext())
System.out.println(it.next().getName());
}
}
执行结果为:
apple
三、SPI的实现原理
SPI的实现主要依靠的就是ServiceLoader类。使用该类加载接口类型(例如:Fruit.class)
ServiceLoader<Fruit> s = ServiceLoader.load(Fruit.class);
虽然是一个load方法,但是并没有加载到指定的服务实现类,这里仅仅是对加载服务实现类做一些准备工作:
- 创建ServiceLoader
- 为service赋值
- 为loader赋值
- 为acc赋值
- 清空providers缓存
- 为lookupIterator赋值,其实就是创建一个LazyIterator延迟迭代器。
然后创建迭代器:
Iterator<Fruit> it = s.iterator();
iterator方法中采用了匿名内部类的方式定义了一个新的迭代器,这个迭代器中每一个方法都是通过调用之前创建好的延迟迭代器lookupIterator来完成的
最后就是进行迭代加载了。
while(it.hasNext())
System.out.println(it.next().getName());
hasNext方法调用了延迟迭代器的hasNext方法,内部调用了hasNextService方法,在这个方法中就会设法去找到指定名称(META-INF/services/+接口全限定名)的资源文件。并完成读取文件内容的操作。
然后执行it.next()操作,这个又会调用延迟迭代器的对应方法hasNext,内部调用了nextService方法,这个方法主要功能就是加载上面从文件中读取到的全限定名称表示的类。并生成实例,将实例保存到providers中。
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
Java基础系列-SPI你认识吗的更多相关文章
- 2015年12月28日 Java基础系列(六)流
2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流
- Java基础系列--static关键字
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/8477914.html 一.概述 static关键字是Java诸多关键字中较常使用的一个,从 ...
- Java基础系列-ArrayList
原创文章,转载请标注出处:<Java基础系列-ArrayList> 一.概述 ArrayList底层使用的是数组.是List的可变数组实现,这里的可变是针对List而言,而不是底层数组. ...
- Java基础系列-Collector和Collectors
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10748925.html 一.概述 Collector是专门用来作为Stream的coll ...
- Java基础系列-二进制操作
原创文章,转载请标注出处:<Java基础系列-二进制操作> 概述 Java源码中涉及到大量的二进制操作,非常的复杂,但非常的快速. Java二进制表示法 首先了解下二进制,二进制是相对十进 ...
- Java基础系列-equals方法和hashCode方法
原创文章,转载请标注出处:<Java基础系列-equals方法和hashCode方法> 概述 equals方法和hashCode方法都是有Object类定义的. publi ...
- Java基础系列-Comparable和Comparator
原创文章,转载请标注出处:<Java基础系列-Comparable和Comparator> 一.概述 Java中的排序是由Comparable和Comparator这两个接 ...
- Java基础系列--HashMap(JDK1.8)
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10022092.html Java基础系列-HashMap 1.8 概述 HashMap是 ...
- 夯实Java基础系列1:Java面向对象三大特性(基础篇)
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...
随机推荐
- 04_Python中的35个关键字
查看Python中的关键字 import keyword print(keyword.kwlist) # 返回一个包含Python关键字的列表 """执行结果 ...
- 干货:不同场景容器内获取客户端源IP的方法
摘要:客户端和容器服务器之间可能存在多种不同形式的代理服务器,那容器中如何获取到客户端真实的源ip呢? k8s已经成为当今容器化的标准,人们在享受容器带来的高效与便利的同时,也遇到一些烦恼:客户端和容 ...
- ui自动化--xpath
xpath //*代表从根节点,查找所有匹配到的元素.在filepath中输入后回车,会发现整个页面所有元素都被虚线选中 //表示跟节点 []代表要用属性定位 @表示要用什么属性 定位完成后,对应页面 ...
- Redis源码笔记--服务器日志和函数可变参数处理server.c
前言 Redis源码中定义了几个和日志相关的函数,用于将不同级别的信息打印到不同的位置(日志文件或标准输出,取决于配置文件的设置),这些函数的定义位于 server.h 和server.c 文件中,包 ...
- sql注入--bool盲注,时间盲注
盲注定义: 有时目标存在注入,但在页面上没有任何回显,此时,我们需要利用一些方法进行判断或者尝试得到数据,这个过程称之为盲注. 布尔盲注: 布尔盲注只有true跟false,也就是说它根据你的注入信息 ...
- 【深入理解Linux内核架构】第3章:内存管理
3.1 概述 内存管理涵盖了许多领域: 内存中物理内存页的管理: 分配大块内存的伙伴系统: 分配小块内存的slab.slub.slob分配器: 分配非连续内存块的vmalloc机制: 进程的地址空间. ...
- 【python】调用sm.ms图床api接口,实现上传图片并返回url
图床简介 sm.ms网站提供免费的图床服务.单图上传大小限制5MB,每次最多上传10张,支持多种图片链接格式和api接口调用. 获取令牌 注册账号并登录,点击User-Dashboard 点击API ...
- 踩坑了,JDK8中HashMap依然会死循环!
是否你听说过JDK8之后HashMap已经解决的扩容死循环的问题,虽然HashMap依然说线程不安全,但是不会造成服务器load飙升的问题. 然而事实并非如此.少年可曾了解一种红黑树成环的场景,=v= ...
- 最火的开源 IDE介绍与安装教程
导读:开发C/C++最好的IDE是什么,尤其对于很多初学者来说用什么IDE比较容易上手,本文将做以介绍,并为您演示如何下载与安装. 本文字数:1015,阅读时长大约:10分钟 (一)最火的开源IDE ...
- Shell学习(三)Shell参数传递
一.传参实例 ##脚本文件内容 #执行的文件名 echo $0; #第一个参数 echo $1; #第二个参数 echo $2; #第三个参数 echo $3; ##调用语句 ./testShell. ...