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
1
2
3
4
5
|
package
com.service;
public
interface
IService {
String
sayHello();
String
getScheme();
}
|
(2)具体服务实现1:HDFSService
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
|
com.impl.HDFSService
com.impl.LocalService
|
(5)测试类
1
2
3
4
5
6
7
8
9
10
11
|
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。
1
2
3
4
5
6
7
8
9
10
11
|
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 ;
}
}
}
|
对应的配置文件:
1
2
3
4
5
6
7
|
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的文章
附:测试用例文件的文件结构
转载自:通过ServiceLoader实现链式处理
分享到:
相关推荐
该文件实现链式队列功能,包含队列的创建queucreat、入队add与出队output,并通过打印显示函数的执行效果。
YQChainTask:Swift链式调用,50行不到代码实现 的 链式任务调用
链式队列
线性表的链式实现
在C语言里面没有模板一说,这里通过用一些极为巧妙的方法来实现了类似于C++的模板功能,使得链式栈的数据可以通过实际需要的类型来决定
链式栈,本程序系数据结构课程课本实例,亲测可用
用C实现,数据结构线性表的顺序和链式实现.
C++ 链式线性表实现
c语言实现的链式链表,对链式链表的初始化,插入,删除,等相关操作!
链式队列的表示和实现源码,包括队列初始化,添加元素、删除元素等操作。
线性表的链式实现(数据结构-严蔚敏)线性表的链式实现(数据结构-严蔚敏)线性表的链式实现(数据结构-严蔚敏)线性表的链式实现(数据结构-严蔚敏)线性表的链式实现(数据结构-严蔚敏)线性表的链式实现(数据...
利用WinDriver实现链式DMA,里面还有对描述符表的详细讲解
JAVA语言实现数据的链式结构 分享下挣挣人气
原理文章:...block 的妙用:结合block和方法的优点实现iOS的链式编程 功能:主要针对段落样式NSMutableParagraphStyle和富文本NSMutableAttributedString进行封装,提升开发效率
实现链式栈和顺序栈的定义,分别创建一个栈。
C语言实现的链式队列
数据结构《线性表的顺序和链式实现及其应用》的实验报告,比较详细|
中国大学MOOC上浙大的《数据结构》课程堆栈链式存储实现的代码,包括空栈的创建,入栈、出栈等基本操作
用链式存储的方式实现字符串的插入操作。 用链式存储的方式实现字符串的创建操作。 用链式存储的方式实现字符串的删除操作。 用链式存储的方式实现字符串的匹配操作。 用链式存储的方式实现字符串的输出操作。