转载请注明源出处: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. 第09章:MongoDB-CRUD操作--文档--修改--update

    ①语法 db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boole ...

  2. 整理mianshi2

    1.性能优化相关https://www.cnblogs.com/cr330326/p/8011523.html 2.CountDownLatchjava共享锁实现原理及CountDownLatch解析 ...

  3. (转)MVC一个页面多个submit

    转自:http://stackoverflow.com/questions/442704/how-do-you-handle-multiple-submit-buttons-in-asp-net-mv ...

  4. Codeforces822 A I'm bored with life

    A. I'm bored with life time limit per test 1 second memory limit per test 256 megabytes input standa ...

  5. set_error_handler

    set_error_handler这个函数的作用是为了防止错误路径泄露 何为错误路径泄露呢? 我们写程序,难免会有问题,而PHP遇到错误时,就会给出出错脚本的位置.行数和原因 有很多人说,这并没有什么 ...

  6. limit

    在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM table  LIMIT [offset ...

  7. HTTP状态代码列表

    httpContext.Response.StatusCode=200 1xx - 信息提示这些状态代码表示临时的响应.客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应. · 100 - ...

  8. Redis持久化之RDB&&AOF的区别

    在说Redis持久化之前,需要搞明白什么是数据库状态这个概念,因为持久化的就是将内存中的数据库状态保存到磁盘上.那么什么是数据库状态呢?Redis是一个key-value数据库服务器,一般默认是有16 ...

  9. FFmpeg4.0笔记:file2rtmp

    Github: https://github.com/gongluck/FFmpeg4.0-study.git #include <iostream> using namespace st ...

  10. 数据库操作类《SqlHelper》

    一.背景 在看了一本书叫<Visual Studio 2010(C#)Windows数据库项目开发>后,觉得很多编程技术需要积累,因为一个简单的项目里包含的技术太多了,容易忘记.每次需要用 ...