文档章节

通过ServiceLoader实现链式处理

华兹格
 华兹格
发布于 2013/02/22 10:58
字数 1316
阅读 8047
收藏 20

ServiceLoader与ClassLoader是Java中2个即相互区别又相互联系的加载器.JVM利用ClassLoader将类载入内存,这是一个类声明周期的第一步(一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况)。详情请参阅:详解Java类的生命周期

ServiceLoader又是什么呢?ServiceLoader:一个简单的服务提供者加载设施。服务 是一个熟知的接口和类(通常为抽象类)集合。服务提供者 是服务的特定实现。提供者中的类通常实现接口,并子类化在服务本身中定义的子类。服务提供者可以以扩展的形式安装在 Java 平台的实现中,也就是将 jar 文件放入任意常用的扩展目录中。也可通过将提供者加入应用程序类路径,或者通过其他某些特定于平台的方式使其可用。……唯一强制要求的是,提供者类必须具有不带参数的构造方法,以便它们可以在加载中被实例化。

通过在资源目录META-INF/services中放置提供者配置文件 来标识服务提供者。文件名称是服务类型的完全限定二进制名称。该文件包含一个具体提供者类的完全限定二进制名称列表,每行一个。忽略各名称周围的空格、制表符和空行。注释字符为'#'('\u0023', NUMBER SIGN);忽略每行第一个注释字符后面的所有字符。文件必须使用 UTF-8 编码。 

以延迟方式查找和实例化提供者,也就是说根据需要进行。服务加载器维护到目前为止已经加载的提供者缓存。每次调用 iterator 方法返回一个迭代器,它首先按照实例化顺序生成缓存的所有元素,然后以延迟方式查找和实例化所有剩余的提供者,依次将每个提供者添加到缓存。可以通过 reload 方法清除缓存。

……

以上来源于Java API里的说明,也许说的很专业,让我们有点晕头转向,我们可以简单的认为:ServiceLoader也像ClassLoader一样,能装载类文件,但是使用时有区别,具体区别如下:(1) ServiceLoader装载的是一系列有某种共同特征的实现类,而ClassLoader是个万能加载器;(2)ServiceLoader装载时需要特殊的配置,使用时也与ClassLoader有所区别;(3)ServiceLoader还实现了Iterator接口。[如有错误或不到的地方敬请指出,互相学习:)]

下面是关于ServiceLoader的简单的例子,仅供参考

(1)基础服务:IService

package com.service;
public interface IService {
	String sayHello();
	String getScheme();
}


(2)具体服务实现1:HDFSService

package com.impl;
import com.service.IService;
public class HDFSService implements IService {
	@Override
	public String sayHello() {
		return "Hello HDFSService";
	}
	@Override
	public String getScheme() {
		return "hdfs";
	}
}


(3)具体服务实现2:LocalService

package com.impl;
import com.service.IService;
public class LocalService  implements IService {
	@Override
	public String sayHello() {
		return "Hello LocalService";
	}
	@Override
	public String getScheme() {
		return "local";
	}
}
(4)配置:META-INF/services/com.service.IService


com.impl.HDFSService
com.impl.LocalService
(5)测试类
package com.test;
import java.util.ServiceLoader;
import com.service.IService;
public class Test {
	public static void main(String[] args) {
		ServiceLoader<IService> serviceLoader  = ServiceLoader.load(IService.class);
		for (IService service : serviceLoader) {
			System.out.println(service.getScheme()+"="+service.sayHello());
		}
	}
}


结果:

hdfs=Hello HDFSService
local=Hello LocalService

可以看到ServiceLoader可以根据IService把定义的两个实现类找出来,返回一个ServiceLoader的实现,而ServiceLoader实现了Iterable接口,所以可以通过ServiceLoader来遍历所有在配置文件中定义的类的实例。


ServiceLoader的应用

(1)Hadoop FileSystem

Hadoop FileSystem就是通过这个机制来根据不同文件的scheme来返回不同的FileSystem。

private static void loadFileSystems() {  
  synchronized (FileSystem.class) {  
    if (!FILE_SYSTEMS_LOADED) {  
      ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class);  
      for (FileSystem fs : serviceLoader) {  
        SERVICE_FILE_SYSTEMS.put(fs.getScheme(), fs.getClass());  
      }  
      FILE_SYSTEMS_LOADED = true;  
    }  
  }  
}
对应的配置文件:

org.apache.hadoop.fs.LocalFileSystem  
org.apache.hadoop.fs.viewfs.ViewFileSystem  
org.apache.hadoop.fs.s3.S3FileSystem  
org.apache.hadoop.fs.s3native.NativeS3FileSystem  
org.apache.hadoop.fs.kfs.KosmosFileSystem  
org.apache.hadoop.fs.ftp.FTPFileSystem  
org.apache.hadoop.fs.HarFileSystem
通过之前的测试类输出对应的scheme和class如下:
file=class org.apache.hadoop.fs.LocalFileSystem  
viewfs=class org.apache.hadoop.fs.viewfs.ViewFileSystem  
s3=class org.apache.hadoop.fs.s3.S3FileSystem  
s3n=class org.apache.hadoop.fs.s3native.NativeS3FileSystem  
kfs=class org.apache.hadoop.fs.kfs.KosmosFileSystem  
ftp=class org.apache.hadoop.fs.ftp.FTPFileSystem  
har=class org.apache.hadoop.fs.HarFileSystem  
hdfs=class org.apache.hadoop.hdfs.DistributedFileSystem  
hftp=class org.apache.hadoop.hdfs.HftpFileSystem  
hsftp=class org.apache.hadoop.hdfs.HsftpFileSystem  
webhdfs=class org.apache.hadoop.hdfs.web.WebHdfsFileSystem 

可以看到FileSystem会把所有的FileSystem的实现都以scheme和class来cache,之后就从这个cache中取相应的值。因此,以后可以通过ServiceLoader来实现一些类似的功能,而不用依赖像Spring这样的第三方框架。

(2)责任链模式

责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

责任连模式可以使用ServiceLoader实现具体服务对象的迭代加载并处理,为了确保此模式的灵活性,建议判断逻辑通过配置文件或数据库的方式,具体实现方式见 参考链接(2) 消灭成堆的……


参考资料:

(1)java.util.ServiceLoader使用

(2)消灭成堆的分支语句之类责任链模式 

(3)转一篇很不错的介绍NetBeans的文章

附:测试用例文件的文件结构

© 著作权归作者所有

华兹格

华兹格

粉丝 161
博文 220
码字总数 82578
作品 0
海淀
高级程序员
私信 提问
加载中

评论(1)

d
develo
说的很详细了,尤其是文件的名称要用二进制这点,这才是关键点,学习了
justlive1/oxygen

oxygen 轻量级Java框架 介绍 一个轻量级Java框架 oxygen-core 核心部分 基于cglib的aop实现 提供缓存管理和基于注解的缓存,内置LocalCache和Ehcache实现,可扩展 配置管理,支持${attrs.key...

justlive1
2018/10/08
0
0
java.util.ServiceLoader使用

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

分享达人
2016/04/15
0
0
轻量级 Java 框架 - JOxygen

JOxygen 轻量级Java框架 介绍 一个轻量级Java框架 oxygen-core 核心部分 基于cglib的aop实现 提供缓存管理和基于注解的缓存,内置LocalCache和Ehcache实现,可扩展 配置管理,支持${attrs.k...

justlive1
2018/11/13
0
0
ServiceLoader的使用

发现ServiceLoader是个类似spring的东西,可以指定接口和实现,通过ServiceLoader去载入。 下面是我的一个例子: Java代码 package com.test2; import java.util.ServiceLoader; import com....

Zero零_度
2016/10/29
19
0
Dubbo内核实现之SPI简单介绍

Dubbo采用微内核+插件体系,使得设计优雅,扩展性强。那所谓的微内核+插件体系是如何实现的呢!即我们定义了服务接口标准,让厂商去实现(如果不了解spi的请谷歌百度下), jdk通过ServiceLo...

明理萝
2018/08/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

优雅的关闭Spring Boot

优雅的关闭Spring Boot 1、实现 TomcatConnectorCustomizer 接口拿到Tomcat的连接获取 Tomcat连接池 2、实现 ApplicationListener<ContextClosedEvent> 监听服务器关闭事件,注册JVM钩子函数...

sowhat
今天
2
0
Python3-Web开发

简介 Web开发框架 什么是Web框架? Web应用程序框架或简单的Web框架表示一组库和模块,使Web应用程序开发人员能够编写应用程序,而不必担心协议,线程管理等低级细节。 virtualenv是一个虚拟...

wuxinshui
今天
3
0
使用技媒体实践编写发布博客

技媒体实践博客 CSDN OSChina 知乎 简书 思否 掘金 51CTO

晨猫
今天
2
0
Lucene

1、什么是全文检索 数据分类 我们生活中的数据总体分为两种:结构化数据和非结构化数据。 结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。 非结构化数据:指不定长或无固...

榴莲黑芝麻糊
昨天
5
0
python到setuptools、pip工具的安装

python安装 基础开发库   apt-get install gcc  apt-get install openssl libssl-dev 安装数据库和开发库   apt-get install mysql-server libmysqld-dev python环境   下载地址...

问题终结者
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部