Most visited

Recently visited

Added in API level 9

ServiceLoader

public final class ServiceLoader
extends Object implements Iterable<S>

java.lang.Object
   ↳ java.util.ServiceLoader<S>


一个简单的服务提供者加载设施。

服务是一组众所周知的接口和(通常是抽象的)类。 服务提供者服务的具体实现。 提供者中的类通常实现接口并将服务本身中定义的类进行子类化。 服务提供者可以以扩展的形式安装在Java平台的实现中,也就是将jar文件放入任何常用的扩展目录中。 提供者也可以通过将它们添加到应用程序的类路径中或通过其他特定于平台的方式来提供。

为了加载,服务由单一类型表示,即单个接口或抽象类。 (可以使用具体类,但不建议这样做。)给定服务的提供者包含一个或多个具体类,这些类可以扩展此服务类型 ,并提供特定于提供者的数据和代码。 提供者类通常不是整个提供者本身,而是包含足够信息的代理,以确定提供者是否能够满足特定请求以及可以按需创建实际提供者的代码。 提供者类的细节往往是高度服务特定的; 没有一个类或接口可以统一它们,所以这里没有定义这种类型。 该工具强制执行的唯一要求是提供程序类必须具有零参数构造函数,以便在加载期间可以对其进行实例化。

A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services. The file's name is the fully-qualified binary name该服务的类型。 该文件包含具体提供者类的完全限定二进制名称列表,每行一个。 围绕每个名称的空格和制表符以及空白行都将被忽略。 注释字符是'#''\u0023'NUMBER SIGN ); 在每行上,第一个注释字符后面的所有字符都将被忽略。 该文件必须以UTF-8编码。

如果一个特定的具体提供者类在多个配置文件中命名,或者多次在同一个配置文件中命名,那么这些重复项将被忽略。 命名特定提供者的配置文件不需要与提供者本身在同一个jar文件或其他分发单元中。 提供者必须可以从最初查询的相同类加载器访问以查找配置文件; 请注意,这不一定是实际加载文件的类加载器。

提供者懒惰地定位并实例化,即按需提供。 服务加载器维护到目前为止已加载的提供者的缓存。 每次调用iterator方法都会返回一个迭代器,该迭代器首先以实例化顺序产生所有缓存元素,然后懒惰地查找并实例化任何剩余的提供程序,并将每个提供程序依次添加到缓存中。 缓存可以通过reload方法清除。

服务加载器总是在调用者的安全上下文中执行。 受信任的系统代码通常应该在特权安全上下文中调用此类中的方法以及它们返回的迭代器的方法。

这个类的实例对于多个并发线程不安全。

除非另有说明,否则将 null参数传递给 此类中的任何方法将导致引发 NullPointerException

示例假设我们有一个服务类型com.example.CodecSet ,用于表示某些协议的编码器/解码器对的集合。 在这种情况下,它是一个具有两种抽象方法的抽象类:

 public abstract Encoder getEncoder(String encodingName);
 public abstract Decoder getDecoder(String encodingName);
Each method returns an appropriate object or null if the provider does not support the given encoding. Typical providers support more than one encoding.

如果 com.example.impl.StandardCodecsCodecSet服务的实现,那么它的jar文件还包含一个名为

 META-INF/services/com.example.CodecSet

该文件包含单行:

 com.example.impl.StandardCodecs    # Standard codecs

CodecSet类在初始化时创建并保存单个服务实例:

 private static ServiceLoader<CodecSet> codecSetLoader
     = ServiceLoader.load(CodecSet.class);

为了找到给定编码名称的编码器,它定义了一个静态工厂方法,该方法遍历已知和可用的提供者,仅当它找到合适的编码器或用完提供者时才返回。

 public static Encoder getEncoder(String encodingName) {
     for (CodecSet cp : codecSetLoader) {
         Encoder enc = cp.getEncoder(encodingName);
         if (enc != null)
             return enc;
     }
     return null;
 }

getDecoder方法的定义类似。

用法说明如果用于提供程序加载的类加载器的类路径包含远程网络URL,则这些URL将在搜索提供程序配置文件的过程中取消引用。

此活动很正常,但可能会导致在Web服务器日志中创建令人费解的条目。 但是,如果Web服务器配置不正确,则此活动可能会导致提供程序加载算法虚假地失败。

当请求的资源不存在时,Web服务器应返回HTTP 404(未找到)响应。 但是,有时候,Web服务器会错误地配置为在这种情况下返回HTTP 200(OK)响应以及有用的HTML错误页面。 当这个类试图将HTML页面解析为提供者配置文件时,这将导致ServiceConfigurationError被抛出。 此问题的最佳解决方案是修复错误配置的Web服务器以返回正确的响应代码(HTTP 404)以及HTML错误页面。

Summary

Public methods

Iterator<S> iterator()

懒惰地加载这个加载程序服务的可用提供者。

static <S> ServiceLoader<S> load(Class<S> service)

使用当前线程的 context class loader为给定的服务类型创建一个新的服务加载器。

static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)

为给定的服务类型和类加载器创建一个新的服务加载器。

static <S> ServiceLoader<S> loadInstalled(Class<S> service)

使用扩展类加载器为给定的服务类型创建一个新的服务加载器。

void reload()

清除该加载程序的提供程序缓存,以便重新加载所有提供程序。

String toString()

返回描述此服务的字符串。

Inherited methods

From class java.lang.Object
From interface java.lang.Iterable

Public methods

iterator

Added in API level 9
Iterator<S> iterator ()

懒惰地加载这个加载程序服务的可用提供者。

此方法返回的迭代器首先以实例化顺序生成提供者缓存的所有元素。 然后它懒惰地加载并实例化任何剩余的提供者,并依次将每个提供者添加到缓存中。

为了实现懒惰,解析可用提供者配置文件和实例化提供者的实际工作必须由迭代器本身完成。 因此,如果提供者配置文件违反指定的格式,或者它命名了一个无法找到并实例化的提供者类,或者实例化该类的结果不能分配给该服务类型,则它的hasNextnext方法可以因此抛出ServiceConfigurationError ,或者在下一个提供者被定位和实例化时引发任何其他类型的异常或错误。 要编写健壮的代码,只需要在使用服务迭代器时捕获ServiceConfigurationError

如果抛出这样的错误,那么迭代器的后续调用将尽最大努力定位和实例化下一个可用的提供者,但通常这种恢复不能得到保证。

Design Note Throwing an error in these cases may seem extreme. The rationale for this behavior is that a malformed provider-configuration file, like a malformed class file, indicates a serious problem with the way the Java virtual machine is configured or is being used. As such it is preferable to throw an error rather than try to recover or, even worse, fail silently.

此方法返回的迭代器不支持删除。 调用其remove方法将导致UnsupportedOperationException被抛出。

Returns
Iterator<S> An iterator that lazily loads providers for this loader's service

load

Added in API level 9
ServiceLoader<S> load (Class<S> service)

使用当前线程的 context class loader为给定的服务类型创建一个新的服务加载器。

这种方便的表单调用

 ServiceLoader.load(service)
is equivalent to
 ServiceLoader.load(service,
                    Thread.currentThread().getContextClassLoader())

Parameters
service Class: The interface or abstract class representing the service
Returns
ServiceLoader<S> A new service loader

load

Added in API level 9
ServiceLoader<S> load (Class<S> service, 
                ClassLoader loader)

为给定的服务类型和类加载器创建一个新的服务加载器。

Parameters
service Class: The interface or abstract class representing the service
loader ClassLoader: The class loader to be used to load provider-configuration files and provider classes, or null if the system class loader (or, failing that, the bootstrap class loader) is to be used
Returns
ServiceLoader<S> A new service loader

loadInstalled

Added in API level 9
ServiceLoader<S> loadInstalled (Class<S> service)

使用扩展类加载器为给定的服务类型创建一个新的服务加载器。

这种方便的方法只需找到扩展类加载器,将其 称为extClassLoader ,然后返回

 ServiceLoader.load(service, extClassLoader)

如果无法找到扩展类加载器,则使用系统类加载器; 如果没有系统类加载器,则使用引导类加载器。

此方法仅适用于仅需安装提供程序的情况。 所得到的服务将仅查找并加载已安装到当前Java虚拟机中的提供程序; 应用程序类路径上的提供者将被忽略。

Parameters
service Class: The interface or abstract class representing the service
Returns
ServiceLoader<S> A new service loader

reload

Added in API level 9
void reload ()

清除该加载程序的提供程序缓存,以便重新加载所有提供程序。

调用此方法后, iterator方法的后续调用将懒惰地查找并从头开始实例化提供程序,就像新创建的加载程序所做的那样。

此方法旨在用于可以将新提供程序安装到正在运行的Java虚拟机中的情况。

toString

Added in API level 9
String toString ()

返回描述此服务的字符串。

Returns
String A descriptive string

Hooray!