ServiceLoader的使用

Posted 异想天开

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ServiceLoader的使用相关的知识,希望对你有一定的参考价值。

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

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

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

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

  我们可以简单的认为:ServiceLoader也像ClassLoader一样,能装载类文件,但是使用时有区别,具体区别如下:(1) ServiceLoader装载的是一系列有某种共同特征的实现类,而ClassLoader是个万能加载器;(2)ServiceLoader装载时需要特殊的配置,使用时也与ClassLoader有所区别;(3)ServiceLoader还实现了Iterator接口。

一、使用示例

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

1、基础服务:IService

public interface IService {
	String sayHello();
	String getScheme();
}

 2、具体服务实现一:HDFSService

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

  具体服务实现二:LocalService

import com.service.IService;
public class LocalService  implements IService {
	@Override
	public String sayHello() {
		return "Hello LocalService";
	}
	@Override
	public String getScheme() {
		return "local";
	}
}

 3、配置:META-INF/services/com.service.IService

com.impl.HDFSService
com.impl.LocalService

 4、测试类

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来遍历所有在配置文件中定义的类的实例。

布署结构可以参考:http://huangyunbin.iteye.com/blog/1883124

二、应用

 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实现具体服务对象的迭代加载并处理,为了确保此模式的灵活性,建议判断逻辑通过配置文件或数据库的方式,具体实现方式见 :https://my.oschina.net/redraiment/blog/105209

                                               http://mogu.io/serviceloader-106

以上是关于ServiceLoader的使用的主要内容,如果未能解决你的问题,请参考以下文章

ServiceLoader的使用

ServiceLoader的使用

何时在 OSGi 之类的东西上使用 ServiceLoader

java浅析JDK中ServiceLoader的源码

使用ServiceLoader辅助责任链模式

Java之ServiceLoader