ServiceLoader与ClassLoader是Java中2个即相互区别又相互联系的加载器.JVM利用ClassLoader将类载入内存,这是一个类声明周期的第一步(一个java类的完整的生命周期会经历加载、链接、初始化、使用、和卸载五个阶段,固然也有在加载或者链接以后没有被初始化就直接被使用的状况)。详情请参阅:详解Java类的生命周期 html
那ServiceLoader又是什么呢?ServiceLoader:一个简单的服务提供者加载设施。服务 是一个熟知的接口和类(一般为抽象类)集合。服务提供者 是服务的特定实现。提供者中的类一般实现接口,并子类化在服务自己中定义的子类。服务提供者能够以扩展的形式安装在 Java 平台的实现中,也就是将 jar 文件放入任意经常使用的扩展目录中。也可经过将提供者加入应用程序类路径,或者经过其余某些特定于平台的方式使其可用。……惟一强制要求的是,提供者类必须具备不带参数的构造方法,以便它们能够在加载中被实例化。 java
经过在资源目录META-INF/services中放置提供者配置文件 来标识服务提供者。文件名称是服务类型的彻底限定二进制名称。该文件包含一个具体提供者类的彻底限定二进制名称列表,每行一个。忽略各名称周围的空格、制表符和空行。注释字符为'#'('\u0023', NUMBER SIGN);忽略每行第一个注释字符后面的全部字符。文件必须使用 UTF-8 编码。
linux
以延迟方式查找和实例化提供者,也就是说根据须要进行。服务加载器维护到目前为止已经加载的提供者缓存。每次调用 iterator 方法返回一个迭代器,它首先按照实例化顺序生成缓存的全部元素,而后以延迟方式查找和实例化全部剩余的提供者,依次将每一个提供者添加到缓存。能够经过 reload 方法清除缓存。 web
…… 数据库
以上来源于Java API里的说明,也许说的很专业,让咱们有点晕头转向,咱们能够简单的认为:ServiceLoader也像ClassLoader同样,能装载类文件,可是使用时有区别,具体区别以下:(1) ServiceLoader装载的是一系列有某种共同特征的实现类,而ClassLoader是个万能加载器;(2)ServiceLoader装载时须要特殊的配置,使用时也与ClassLoader有所区别;(3)ServiceLoader还实现了Iterator接口。[若有错误或不到的地方敬请指出,互相学习:)] apache
下面是关于ServiceLoader的简单的例子,仅供参考 缓存
(1)基础服务:IService 框架
package com.service; public interface IService { String sayHello(); String getScheme(); }
(2)具体服务实现1:HDFSService ide
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 oop
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以下:
能够看到FileSystem会把全部的FileSystem的实现都以scheme和class来cache,以后就从这个cache中取相应的值。所以,之后能够经过ServiceLoader来实现一些相似的功能,而不用依赖像Spring这样的第三方框架。
(2)责任链模式
责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任连模式可使用ServiceLoader实现具体服务对象的迭代加载并处理,为了确保此模式的灵活性,建议判断逻辑经过配置文件或数据库的方式,具体实现方式见 参考连接(2) 消灭成堆的……
参考资料:
附:测试用例文件的文件结构