S
- 此装载器要加载的服务类型
public final class ServiceLoader<S> extends Object implements Iterable<S>
一个服务是一组众所周知的接口(通常是抽象的)类。 服务提供商是服务的具体实现。 提供者中的类通常实现接口并对服务本身定义的类进行子类化。 服务提供商可以以Java扩展的形式安装在Java平台的实现中,也就是将jar文件放置到任何通常的扩展目录中。 提供商也可以通过将它们添加到应用程序的类路径或某些其他平台特定的方式来提供。
为了加载,服务由单一类型表示,即单个接口或抽象类。 (可以使用一个具体的类,但不建议使用)。给定服务的提供者包含一个或多个具体的类,以扩展此服务类型 ,并提供特定于该提供者的数据和代码。 提供程序类通常不是整个提供程序本身,而是一个包含足够信息的代理,以确定提供程序是否能够满足特定请求以及可以根据需要创建实际提供程序的代码。 提供者类的细节往往是高度服务特定的; 没有一个类或接口可能会统一它们,所以在这里不定义这样的类型。 该工具强制执行的唯一要求是提供程序类必须具有零参数构造函数,以便在加载期间实例化它们。
A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services.该文件的名称是服务类型的全资格binary name 。 该文件包含具体提供程序类的完全限定二进制名称列表,每行一个。 忽略每个名称周围的空格和制表符,以及空白行。 注释字符为'#' ( '\u0023' , NUMBER SIGN ); 在每行上,忽略第一个注释字符之后的所有字符。 文件必须以UTF-8编码。
如果一个特定的具体提供程序类在多个配置文件中命名,或者在同一配置文件中多次命名,则忽略重复的配置文件。 命名特定提供者的配置文件不需要与提供者本身在同一个jar文件或其他分发单元中。 提供程序必须可以从初始查询的相同类加载器访问以查找配置文件; 请注意,这不一定是文件实际加载的类加载器。
供应商懒惰地定位和实例化,也就是按需。 服务加载器维护到目前为止已经加载的提供程序的缓存。 每次调用iterator
方法都会返回一个迭代器,首先按照实例化顺序生成缓存的所有元素,然后懒惰地定位和实例化任何剩余的提供程序,依次将每个元素添加到缓存中。 缓存可以通过reload
方法清除。
服务加载器总是在调用者的安全上下文中执行。 受信任的系统代码应通常调用此类中的方法,以及从特权安全上下文中返回的迭代器的方法。
此类的实例不能安全地被多个并发线程使用。
除非另有说明,否则传递null参数到此类中的任何方法将导致抛出NullPointerException
。
示例假设我们有一个服务类型com.example.CodecSet ,用于表示一些协议的编码器/解码器对的集合。 在这种情况下,它是一个抽象类,有两个抽象方法:
如果提供程序不支持给定的编码,每个方法返回一个适当的对象或null 。 典型的提供商支持多个编码。public abstract Encoder getEncoder(String encodingName); public abstract Decoder getDecoder(String encodingName);
如果com.example.impl.StandardCodecs是CodecSet服务的实现,那么它的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(未找到)响应。 然而,有时,网络服务器错误地配置为在这种情况下返回HTTP 200(OK)响应以及有用的HTML错误页面。 这将导致一个ServiceConfigurationError
当这个类尝试解析HTML页面作为提供者配置文件被抛出。 解决此问题的最佳方法是修复配置错误的Web服务器,以返回正确的响应代码(HTTP 404)以及HTML错误页面。
Modifier and Type | Method and Description |
---|---|
Iterator<S> |
iterator()
懒洋洋地加载这个装载机服务的可用提供商。
|
static <S> ServiceLoader<S> |
load(类<S> service)
使用当前线程的
context class loader为给定的服务类型创建一个新的服务加载器。
|
static <S> ServiceLoader<S> |
load(类<S> service, ClassLoader loader)
为给定的服务类型和类加载器创建一个新的服务加载器。
|
static <S> ServiceLoader<S> |
loadInstalled(类<S> service)
使用扩展类加载器为给定的服务类型创建一个新的服务加载器。
|
void |
reload()
清除此加载程序的提供程序缓存,以便所有提供程序都将重新加载。
|
String |
toString()
返回描述此服务的字符串。
|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
forEach, spliterator
public void reload()
调用此方法后,iterator
方法的后续调用将从头开始轻松查找和实例化提供程序,就像新创建的加载程序一样。
此方法适用于将新提供程序安装到正在运行的Java虚拟机中的情况。
public Iterator<S> iterator()
该方法返回的迭代器首先以实例化顺序生成提供程序缓存的所有元素。 然后它懒惰地加载和实例化任何剩余的提供商,依次将每个提供者添加到缓存。
为了实现懒惰,解析可用的提供者配置文件和实例提供者的实际工作必须由迭代器本身完成。 因此 ,如果提供商配置文件违反了指定的格式,或者如果命名了一个无法找到和实例化的提供程序类,或者实例化该类的结果不能分配给服务类型,那么它的hasNext
和next
方法可能会抛出一个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
。
public static <S> ServiceLoader<S> load(类<S> service, ClassLoader loader)
S
- 服务类的类
service
- 表示服务的接口或抽象类
loader
-类加载器用于加载提供者配置文件和提供者类,或
null如果系统类加载器(或,如若不然,引导类加载器)是用来
public static <S> ServiceLoader<S> load(类<S> service)
调用这种方便的方式的形式
相当于ServiceLoader.load(service)
ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
S
- 服务类型的类
service
- 表示服务的接口或抽象类
public static <S> ServiceLoader<S> loadInstalled(类<S> service)
这种方便的方法只是定位扩展类加载器,调用它extClassLoader ,然后返回
ServiceLoader.load(service, extClassLoader)
如果无法找到扩展类加载器,则使用系统类加载器; 如果没有系统类加载器,则使用引导类加载器。
此方法仅在需要安装的提供程序时使用。 所产生的服务将只找到并加载已安装到当前Java虚拟机中的提供程序; 应用程序的类路径上的提供程序将被忽略。
S
- 服务类的类
service
- 表示服务的接口或抽象类