转载请注明源出处:http://www.cnblogs.com/lighten/p/6946683.html

1.简介

  JDK1.6之后,java.util包下多了一个类ServiceLoader,其实现了Iterable接口(可以直接进行for-each loop)。这个类的主要作用是提供了一种服务发现机制,并没有什么深奥的内容。实现过程也十分简单,下面通过一个例子来详细讲解一下如何使用和其实现过程。本文基于jdk1.8。

2.例子

  ServiceLoader的使用是要在根目录有一个文件夹META-INF/services/,其主要是对这个目录进行扫描,文件名是你需要提供服务的类(接口)全称(即包名.类名)。类中的内容,一行就是改接口的一个具体的实现类。包结构如下:

  服务的定义和实现具体如下:

public interface TestService {

	public String sayHello();

}

public class TestServiceImpl1 implements TestService {

	@Override
public String sayHello() {
return "hello, test1";
} } public class TestServiceImpl2 implements TestService { @Override
public String sayHello() {
return "hello, test2";
} }

  配置文件就是实现类的类全称:

com.java.util.test.TestServiceImpl1
com.java.util.test.TestServiceImpl2

  配置完成后就是最主要的使用方法了:

public class ServiceLoaderTest {

	public static void main(String[] args) {
ServiceLoader<TestService> loader = ServiceLoader.load(TestService.class);
for(TestService service : loader) {
System.out.println(service.sayHello());
}
} }

  运行一下结果如下:

  使用起来也很简单,就是通过静态方法load进行加载,然后通过for-each循环遍历,使用这个实现类。

3.源码解读

  ServiceLoader解析服务并不是加载就立刻解析的,其采取的是懒加载的方式,也就是第一次使用这个loader对象的时候才进行解析。

  1.先看属性:

  这里就定义了读取的文件名,service是需要加载的类,loader是类加载器,默认使用当前加载器,providers是服务提供者,lookupIterator就是懒加载的具体实现了。

  2.再看loader方法:

  loader方法就是初始化了一些属性,清空了providers。

  3.关键的iterator()方法,这个是Iterable接口需要实现的一个方法:

  其遍历,是先通过providers来遍历,因为解析完成后这里应该是有值的,如果没值,就通过lookupIterator去遍历,这里也就看出并不是loader就开始读取然后解析,而是在遍历的时候,没找到解析的值,再通过设置的懒加载遍历器,去解析遍历。

  4.核心的LazyIterator,其实现了Iterator接口,next和hasNext实际上调用的是其另两个方法,nextService与hasNextService

  上面代码很简单,就是读取META-INF/services文件夹下,所加载类的类全称名的文件,通过parse方法解析。

  nextService方法也很简单,就是通过实现类的类全称,通过Class.forName进行加载。然后判断该实现类是不是加载类的子类,service.isAssignableFrom,再通过service.cast()方法进行转换成所加载的类。

  5.parse解析文件步骤:

  用utf-8的格式读取,然后调用parseLine方法,一行行读取到name这个迭代器中。

  读取一行,截取#注释前面的内容,通过trim方法去掉两端空格。若还有值,则判断是否有空格或制表符,有即不符合规则,查看是不是Java标识的开头。都满足规则,如果providers中没有且未解析过相同的,就放入迭代器中。

  至此,这个解析过程就明了了,就是读取指定文件夹的指定文件,文件中存的类全称,通过Class.forName,拿到字节码,再通过class.newInstance方法获得实例,将其cast成所要加载的类。

Java之ServiceLoader的更多相关文章

  1. java.util.ServiceLoader的用法

    在很多开源组件里经常会看到java.util.ServiceLoader的使用,这里给大家介绍下怎么通过ServiceLoader找到一个接口的所有实现类. 我们新建一个接口Hello public ...

  2. java.util.ServiceLoader使用

    近期在项目中需要实现能在配置文件中定义多个统一接口类型的类,可以在程序中获取到所有配置的类,刚开始打算配置到properties中,然后去程序读取,感觉这种方式不太灵活,于是,研究研究java中有没有 ...

  3. 【Java】ServiceLoader源码分析

    ServiceLoader主要的功能是用来完成对SPI的provider的加载. 先看下它的成员: public final class ServiceLoader<S> implemen ...

  4. Java ServiceLoader(SPI)学习

    1. 几个不错的关于ServiceLoader的文章,大家可以先参考一下 1) http://www.myexception.cn/program/1355384.html 这篇的后面的问题分析不错 ...

  5. 【java编程】ServiceLoader使用看这一篇就够了

    转载:https://www.jianshu.com/p/7601ba434ff4 想必大家多多少少听过spi,具体的解释我就不多说了.但是它具体是怎么实现的呢?它的原理是什么呢?下面我就围绕这两个问 ...

  6. Java SPI机制:ServiceLoader实现原理及应用剖析

    一.背景 SPI,全称Service Provider Interfaces,服务提供接口.是Java提供的一套供第三方实现或扩展使用的技术体系.主要通过解耦服务具体实现以及服务使用,使得程序的可扩展 ...

  7. Java DNS查询内部实现

    源码分析 在Java中,DNS相关的操作都是通过通过InetAddress提供的API实现的.比如查询域名对应的IP地址: String dottedQuadIpAddress = InetAddre ...

  8. java中的SPI机制

    1 SPI机制简介 SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的.在java.util.ServiceLoader的文档里 ...

  9. JAVA流程控制

    JAVA流程控制 example1: --输出九九乘法表 public class chengfabiao { public static void main (String[] args){     ...

随机推荐

  1. IntelliJ IDEA 2017版 使用笔记(十二) 其他操作:IDEA 快捷键

    其他操作   文件操作: 一.文件操作       新建文件ctrl+shift+n    二.复制当前文件       快捷键:F5   三.移动当前文件       快捷键 :F6       文 ...

  2. java se的那些细节

    局部变量:方法体内或语句块内,不能有修饰符 成员变量:与类的对象共存,可以有修饰符 类属性:与类共存,可以有修饰符 一.局部变量:必须先赋值,才能使用,如果不赋初值,则会报错,即没有默认的始使值,而基 ...

  3. Android: Custom View和include标签的区别

    Custom View, 使用的时候是这样的: <com.example.home.alltest.view.MyCustomView android:id="@+id/customV ...

  4. (转)MyEclipse10下创建web项目并发布到Tomcat

    转自:http://blog.sina.com.cn/s/blog_699d3f1b01012spf.html   MyEclipse10下创建web项目并发布到Tomcat 1.软件安装(不作详细描 ...

  5. CentOS FTP服务器系统套件全面讲解

    对大家推荐很好使用的CentOS FTP系统,像让大家对CentOS FTP系统有所了解,然后对CentOS FTP系统全面讲解介绍,希望对大家有用. 1.vsFTPd,目前常用CentOS FTP服 ...

  6. spark 中划分stage的思路

    窄依赖指父RDD的每一个分区最多被一个子RDD的分区所用,表现为 一个父RDD的分区对应于一个子RDD的分区 两个父RDD的分区对应于一个子RDD 的分区. 宽依赖指子RDD的每个分区都要依赖于父RD ...

  7. Python自动化开发 - Python操作MySQL

    本篇对于Python操作MySQL主要使用两种方式: 原生模块 pymsql ORM框架 SQLAchemy 一.pymysql pymsql是Python中操作MySQL的模块,其使用方法和mysq ...

  8. OS基础:动态链接库(二)

    1.vc6.0新建工程MFC AppWizard[dll]工程 命名LptMfcDll1 2.在lptMfcDll1.h添加函数名声明 添加的代码: //lptAddBegin void lptMfc ...

  9. [leetcode 14]Longest Common Prfix

    1 题目: Write a function to find the longest common prefix string amongst an array of strings. Hide Ta ...

  10. [转载]持续交付和DevOps的前世今生

    作者/分享人:乔梁,20年IT老兵,腾讯公司高级管理顾问,敏捷和精益开发专家,持续交付领域先行者.曾就职于百度,国内多个知名互联网公司的企业教练. 历年QCon技术大会的讲师和专题出品人. 这是一个新 ...