首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java ServiceLoader解释

Java ServiceLoader解释
EN

Stack Overflow用户
提问于 2017-07-29 09:04:58
回答 1查看 3.7K关注 0票数 9

我试图理解Java文档的概念、工作机制和具体的用例,但发现官方的文档太抽象和混乱。

首先,文档概述了服务服务提供者。服务是打包在jar存档(API库)中的一组接口和抽象类。服务提供者是一组实现或扩展API的类,打包在一个不同的jar文件(提供者库)中。

到目前为止还不错,但是文档会变得很混乱。

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

那么,究竟什么是服务类型的提供者类?我的印象是,服务类型是API库中的立面,提供者类是提供者库中这个facade接口的实现,这个类是ServiceLoader实际加载的类。这是正确的吗?但对我来说,所有的组件是如何联系在一起的,这仍然没有多大意义。

提供者类作为代理来决定提供者是否能够满足特定的请求以及能够根据需要创建实际提供程序的代码意味着什么?没有统一类型可以定义在哪里?基本上,这一段都是令人困惑的,我想通过一个具体的例子听到更容易理解的解释。

然后关于提供程序配置文件..。

服务提供者通过将提供者配置文件放置在资源目录META/services中来标识。文件名是服务类型的完全限定的二进制名称。该文件包含具体提供程序类的完全限定二进制名称的列表,每行一个. 命名特定提供程序的配置文件不需要与提供程序本身位于同一个jar文件或其他分发单元中。提供程序必须可以从最初被查询的同一类加载器中访问,以定位配置文件;请注意,这不一定是实际加载文件的类加载器。

这是否意味着对于服务类型为org.foo.BarServiceType的API,在类路径中必须存在具有实现该类型的类的提供者jar,以及列出此提供程序类的META-INF/services/org.foo.BarServiceType命名的提供程序配置文件,所有这些都由加载ServiceLoader以在API上查找和绑定提供程序的同一个Classloader访问?

从类加载器的角度来看,可访问意味着提供者配置文件和提供者库可以在包之外提供,可以从层次结构(即容器或其他中间件)的上层提供。

提供程序配置文件列出了提供程序类,并且可能绑定在提供程序包中(如果绑定,它为什么要列出多个类?)或者从外面来。但是哪种方法更常见:在提供程序之间提供配置文件,还是在API库本身中提供列出一组受支持的提供程序的文件?还是后者是一种误解?

最后关于ServiceLoader

在哪里实际实例化并调用ServiceLoader来加载服务提供者?这种情况是否发生在API库提供的工厂方法中?例如,LoggingFactory.getLogger(clazz) of SLF4J内部委托给ServiceLoaderServiceLoader使用反射读取提供程序配置文件并加载服务?

服务加载机制如何处理这样的情况:哪里有多个提供程序及其配置文件,或者有提供程序配置文件条目,而不是类本身?

在日志记录框架之外,ServiceLoader的其他一些具体用例是什么?在流行的框架(如Java、Spring和Hibernate )下,它被使用了多少?对于松散耦合API-提供者绑定的服务加载机制,有哪些替代方案?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-30 01:29:51

服务类型是传递给ServiceLoader.load或ServiceLoader.loadInstalled的接口或抽象类。提供程序是该接口或抽象类的具体实现。

由于服务通常由大量的功能组成,所以当ServiceLoader扫描这些类时,如果没有立即全部加载这些类,则非常有用。相反,更好的设计是一个很小的类,它提供了对主要功能的访问。例如,ServiceLoader.load(FileSystemProvider.class)不加载能够处理特定文件系统集的整个库;而是加载一个FileSystemProvider对象,该对象能够初始化该库,前提是应用程序选择使用它。这允许提供者本身保持轻量级。

这是否意味着对于服务类型为org.foo.BarServiceType的API,在类路径中必须存在具有实现此类型和META/services/org.foo.BarServiceType命名提供者配置文件的类的提供者jar,这些类都由加载ServiceLoader以在API上查找和绑定提供者的同一个Classloader访问?

是。通常,这是非常简单的;例如,包含org.foo.BarServiceType实现类的org.foo.BarServiceType文件还包含一个META-INF/services/org.foo.BarServiceType条目,其内容由一行文本组成。

如果捆绑的话,它为什么要列出多个类?

有些服务提供者只能处理某些情况。一个例子是IIORegistry类(它没有提到ServiceLoader,实际上在将ServiceLoader添加到Java之前很久就已经存在了,但功能与ServiceLoader相同)。可能有一个ImageReaderSpi的实现为PNG提供ImageReaders,另一个ImageReaderSpi为JPEG提供ImageReaders,等等。每个这样的服务提供者类(即ImageReaderSpi的每个具体实现)在其canDecodeInput方法中都有不同的逻辑,因此除非应用程序实际需要它们,否则不会创建重量级ImageReader实例。

但是哪种方法更常见:在提供程序之间提供配置文件,还是在API库本身中提供列出一组受支持的提供程序的文件?

如果我正确理解您的问题,答案是在实践中,SPI描述符总是与它命名的提供者类位于同一个.jar文件中。

至于问题的最后一部分:我不认为记录器框架使用ServiceLoader。有关使用ServiceLoader的示例,请查看以.spi结尾的Java包(java.awt.im.spi、java.nio.channels.spi、java.nio.charset.spi等)。他们中的大多数人没有说他们依赖ServiceLoader,但是他们都描述了他们的查找行为,而且您会发现它几乎总是与ServiceLoader的相同。

服务加载机制如何处理这样的情况:哪里有多个提供程序及其配置文件,或者有提供程序配置文件条目,而不是类本身?

在类路径中存在多个提供者的情况下,ServiceLoader只需在其爱尔兰人中返回所有这些提供者。

对于不正确的配置文件,将从ServiceLoader的Iterator的下一个()方法抛出一个ServiceConfigurationError。从文件中:

加载服务提供程序时出错时引发的错误。 在以下情况下将引发此错误:

  • 提供程序配置文件的格式违反了规范;
  • IOException在读取提供程序配置文件时发生;
  • 无法找到在提供程序配置文件中命名的具体提供程序类;
  • 具体的提供者类不是服务类的子类;
  • 不能实例化具体提供程序类;或
  • 其他类型的错误也会发生。

总结如下:

  • 服务提供者实现类通常与META/services描述符文件位于同一个.jar中。
  • 服务提供者类通常是一个轻量级类,它允许应用程序访问更重的类,前提是并且只有当应用程序决定需要它们时。
  • Java的许多部分使用ServiceLoader,特别是*.spi包。
  • 如果一个服务有许多实现,则在迭代器中返回所有实现。
  • 不正确的描述符会导致ServiceConfigurationError。
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45387473

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档