ServiceLoader源代码分析

1.ServiceLoader可以用来做什么

我比较喜欢用通俗的语言来说明,ServiceLoader我用通俗的语言来讲的话,就是可以通过配置文件灵活的来指定一个接口的实现类,再用ClassLoader来把这些实现类加载到内存中。这么做的好处是什么,这么做的好处是什么?显而易见,使得我们写的程序更加灵活,更加容易扩展。ServiceLoader是Java的SPI实现。

2.直接上个sample

定义一个接口:

两个实现类:


配置文件:

配置文件一定要放到META-INF/service 文件夹下面。并且文件名字必须是接口的包名加上类名(接口的全类名)

通过ServiceLoader来加载指定的实现类:

3.运行效果


我们可以把配置文件里面的com.smallcode.service.WxPayService删掉,执行的结果如下:

只剩下支付宝支付的字样了。
可以看出已经通过ServiceLoader把指定的实现类加载进去了。

3.ServiceLoader核心源代码分析

以上简单的演示下了ServiceLoader的效果,下面看下ServiceLoader核心源代码,来具体看下ServiceLoader是如何实现的。
沿着main方法里面的ServiceLoader.load方法追踪源代码:

// ServiceLoader.java
public static <S> ServiceLoader<S> load(Class<S> service) {ClassLoader cl = Thread.currentThread().getContextClassLoader();return ServiceLoader.load(service, cl);}

该方法调用了load(Class<S> service,ClassLoader loader) 方法:

public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){return new ServiceLoader<>(service, loader);}

调用了构造函数 ServiceLoader(Class<S> svc, ClassLoader cl) :

private ServiceLoader(Class<S> svc, ClassLoader cl) {service = Objects.requireNonNull(svc, "Service interface cannot be null");loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;reload();}

调用了reload() 方法:

public void reload() {providers.clear();lookupIterator = new LazyIterator(service, loader);}

追踪到一个LazyIterator,一个迭代器。
我们再看ServiceLoader 实现了 Iterable接口

 public final class ServiceLoader<S>implements Iterable<S>

当我们的在main方法里面通过foreach的时候,会调用ServiceLoader类里面的iterator方法返回的迭代器,进行循环迭代。

public Iterator<S> iterator() {return new Iterator<S>() {Iterator<Map.Entry<String,S>> knownProviders= providers.entrySet().iterator();public boolean hasNext() {if (knownProviders.hasNext())return true;return lookupIterator.hasNext();}public S next() {if (knownProviders.hasNext())return knownProviders.next().getValue();return lookupIterator.next(); // <1>}public void remove() {throw new UnsupportedOperationException();}};}

这里涉及到迭代器原理和foreach,在这里不做详细介绍。

接着往下追踪代码:


拼接配置文件路径,可以看出路径是META-INF/services/接口全类名。

根据获取的路径读取文件,返回一个集合,配置文件每行对应集合一条数据。

private Iterator<String> parse(Class<?> service, URL u)throws ServiceConfigurationError{InputStream in = null;BufferedReader r = null;ArrayList<String> names = new ArrayList<>();try {in = u.openStream();r = new BufferedReader(new InputStreamReader(in, "utf-8"));int lc = 1;while ((lc = parseLine(service, u, r, lc, names)) >= 0);} catch (IOException x) {fail(service, "Error reading configuration file", x);} finally {try {if (r != null) r.close();if (in != null) in.close();} catch (IOException y) {fail(service, "Error closing configuration file", y);}}return names.iterator();}

在nextService(迭代器中next方法调用了nextService)可以看出,通过ClassLoader加载刚刚从配置文件里面获取到实现类。然后返回该实现类。

4.总结

本文首先简单的介绍了ServiceLoader,在编写了一个实例,最后通过源代码分析ServicerLoader具体的实现。总体来说ServiceLoader实现比较简单。

Java SPI机制原理——丑时相关推荐

  1. Java SPI机制原理和使用场景

    SPI的全名为Service Provider Interface.这个是针对厂商或者插件的.一般来说对于未知的实现或者对扩展开放的系统,通常会把一些东西抽象出来,抽象的各个模块,往往有很多不同的实现 ...

  2. Java SPI机制详解

    Java SPI机制详解 1.什么是SPI? 2.SPI的用途 Driver实现 Mysql DriverManager实现 spi工具类`ServiceLoader` 将自己注册到驱动管理器的驱动列 ...

  3. Java SPI机制实现插件化扩展功能

    Java SPI机制实现插件化扩展功能 1.背景 我们有一个图数据库的服务,用户希望在不修改现有源代码的情况下扩展自定义的分词器,达到可插件式扩展功能的目标. 通过Java的SPI机制实现插件式的扩展 ...

  4. Flink从入门到精通100篇(十一)-Java SPI 机制在 Flink SQL 中的应用

    Java SPI 机制简介 Java SPI机制,即Java Service Provider Interface,是Java提供的基于"接口编程 + 策略模式 + 配置文件"组合 ...

  5. java反射原理_java反射原理是什么?java反射机制原理详解

    前面给大家介绍了一下什么是java反射机制,那么下面要给大家介绍的就是java反射机制的原理,那么它的原理究竟是怎样的呢?下面就通过下面来做一下详细的了解吧. 首先我们再来介绍一下java反射机制. ...

  6. java spi机制_Java是如何实现自己的SPI机制的? JDK源码(一)

    注:该源码分析对应JDK版本为1.8 1 引言 这是[源码笔记]的JDK源码解读的第一篇文章,本篇我们来探究Java的SPI机制的相关源码. 2 什么是SPI机制 那么,什么是SPI机制呢? SPI是 ...

  7. java spi技术,Java SPI机制

    Java组件一个更为人熟知的名词"服务",与流行的微服务有所区别. 以往加载JDBC驱动使用如下方式:Class.forName() Java 1.6引入SPI机制,使用Drive ...

  8. java spi机制_Java 双亲委派机制的破坏—SPI机制

    作者:程序猿微录 出自:TinyRecord 原文:tinyice.cn/articles/123 Java 双亲委派机制的破坏-SPI机制 在Java的类加载机制中,默认的就是双亲委派机制,这种委派 ...

  9. 深入理解java SPI机制

    What? SPI机制(Service Provider Interface)其实源自服务提供者框架(Service Provider Framework,参考[EffectiveJava]page6 ...

最新文章

  1. 使用自变分原理改进正则化核回归:通过变分法推导和推广Nadaraya-Watson估计
  2. Javascript在IE中的有趣错误
  3. Google首席软件工程师Joshua Bloch谈如何设计一款优秀的API【附PPT】
  4. Python 技术篇-读取文件,将内容保存dict字典中。去掉字符串中的指定字符方法,dict字典的遍历
  5. 家庭用户的linux,一个极普通家庭用户对于ubuntu的21天使用心得
  6. C#学习知识库2.0版
  7. thingsboard源码结构解析
  8. 在大流行的世界中如何建立技术社区
  9. Docker使用-Hello World
  10. 技术管理中的“沟通”
  11. 前端集成解决方案(转)
  12. ggplot2作图详解:图层语法和图形组合
  13. 3.JUC线程高级-同步容器 ConcurrentHashMap
  14. cocos2d-x 3.1.1 学习笔记[21]cocos2d-x 创建过程
  15. html颜色转换rgba,RGB颜色在线转换
  16. Linux驱动模块Makefile编写
  17. 鸡和兔关在一个笼子里,鸡有2只脚,兔有4只脚,螃蟹 ;递归
  18. MyEclipse中maven项目中WEBROOT目录问题
  19. 豆瓣电影评分分析(数据分析)
  20. 团体程序设计天梯赛-习题集部分题解(大牛勿喷)

热门文章

  1. 时序分析基础(2)——input_delay
  2. Qt5.9关闭子窗口时执行特定代码(析构函数、关闭窗口)(setAttribute(Qt::WA_DeleteOnClose)、closeEvent(QCloseEvent* event))
  3. 工赋开发者社区 | Adobe豪掷200亿美元收购Figma,开发者却将其骂上了“热搜”
  4. 解析shodan下载数据的json
  5. 各种语音编码带宽计算
  6. 基于javaweb的电影在线观看系统(java+ssm+jsp+layui+mysql)
  7. android viewpager 缓存,ViewPager2重大更新,支持offscreenPageLimit
  8. 这款跨平台开发框架厉害了,叫泰罗·奥特曼
  9. js获取、今日、昨日的开始与结束时间戳
  10. Ijkplayer 初始化和prepare源码分析