Java之ServiceLoader

  转载请注明源出处: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成所要加载的类。

时间: 2024-12-22 05:20:14

Java之ServiceLoader的相关文章

【JAVA】使用Java SPI ServiceLoader进行Java应用插件模块化开发

背景:在进行业务定制时需要考虑不同接口的服务实现,每个局点所要求的接口大体都不一致,要求接口服务能够插件化方式提供: 方案分析: 1)采用OSGI框架进行开发,但是考虑到OSGI的框架太重,需要引入的东西比较多,放弃了该方案: 2)采用Java class loader动态加载外部jar机制,动态加载定制的接口服务类,这种方式实现比较复杂,需要完成指定接口服务类的文件加载,同时需要能查找到所有接口服务类,作为备选方案: 3)使用java service provider interface(SP

java spi

SPI的全名为Service Provider Interface.普通开发人员可能不熟悉,因为这个是针对厂商或者插件的.在java.util.ServiceLoader的文档里有比较详细的介绍.究其思想,其实是和"Callback"差不多.“Callback”的思想是在我们调用API的时候,我们可以自己写一段逻辑代码,传入到API里面,API内部在合适的时候会调用它,从而实现某种程度的“定制”. 典型的是Collections.sort(List<T> list,Comp

Java DNS查询内部实现

源码分析 在Java中,DNS相关的操作都是通过通过InetAddress提供的API实现的.比如查询域名对应的IP地址: String dottedQuadIpAddress = InetAddress.getByName( "blog.arganzheng.me" ).getHostAddress(); 或者反过来IP对应域名: InetAddress[] addresses = InetAddress.getAllByName("8.8.8.8"); // i

ServiceLoader的使用

ServiceLoader与ClassLoader是Java中2个即相互区别又相互联系的加载器.JVM利用ClassLoader将类载入内存,这是一个类声明周期的第一步(一个java类的完整的生命周期会经历加载.连接.初始化.使用.和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况). 那ServiceLoader又是什么呢?ServiceLoader:一个简单的服务提供者加载设施.服务 是一个熟知的接口和类(通常为抽象类)集合.服务提供者 是服务的特定实现.提供者中的类通

使用ServiceLoader辅助责任链模式

在项目中,常常会遇到这么一种场景,即对一批/一种/一堆数据,进行链式的处理.举个栗子,拿到一个task后,需要对这个task进行校验处理.状态变更处理.计算并回填数据处理等等各种处理,这种情况下,最适合的编码方式就是使用责任链了: 定义一个taskprocessor接口: public interface TaskProcessor { boolean process(Task task, TaskConfigDTO config); } 然后,再定义诸多的实现类,来进行处理,可以使代码更加优雅

Java的SPI机制与简单的示例

一.SPI机制 这里先说下SPI的一个概念,SPI英文为Service Provider Interface单从字面可以理解为Service提供者接口,正如从SPI的名字去理解SPI就是Service提供者接口:我对SPI的定义:提供给服务提供厂商与扩展框架功能的开发者使用的接口. 在我们日常开发的时候都是对问题进行抽象成Api然后就提供各种Api的实现,这些Api的实现都是封装与我们的Jar中或框架中的虽然当我们想要提供一种Api新实现时可以不修改原来代码只需实现该Api就可以提供Api的新实

Java 最常用类(前1000名) 来自GitHub 3000个项目

这篇文章主要介绍了最常用的1000个Java类(附代码示例),需要的朋友可以参考下 分析Github 3000个开源项目,粗略统计如下.括号内的数字是使用频率 0-3000. 下面的列表显示不全,完整的请看完整列表. 1.java.util.List (2889) 2.java.util.ArrayList (2831)3.java.io.IOException (2813)4.java.util.Map (2592)5.java.util.HashMap (2541)6.java.io.Fil

java的spi 的简单应用

1.什么是java的spi SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制. 目前有不少框架用它来做服务的扩展发现, 简单来说,它就是一种动态替换发现的机制, 举个例子来说, 有个接口,想运行时动态的给它添加实现,你只需要添加一个实现. 具体是在JAR包的"src/META-INF/services/"目录下建立一个文件,文件名是接口的全限定名,文件的内容可以有多行,每行都是该接口对应的具体实现类的全限定名. 2.运用场景

Java的SPI机制示例代码

定义接口 package com.hiwzc.myspi; public interface Demo {     void dosomething(); } 提供两种模拟实现 package com.hiwzc.myspi.impl; import com.hiwzc.myspi.Demo; public class DemoAImpl implements Demo{     @Override     public void dosomething() {         System.o