【发布时间】:2018-01-05 08:22:00
【问题描述】:
我正在尝试理解JavaServiceLoader的概念、工作机制和具体用例,但发现官方的documentation过于抽象和混乱。
首先,文档概述了服务和服务提供商。 服务是封装在 jar 档案(API 库)中的一组接口和抽象类。服务提供者是一组实现或扩展 API 的类,打包在不同的 jar 文件(提供者库)中。
到目前为止一切都很好,但是文档变得混乱。
为了加载的目的,服务由单一类型表示,即单一接口或抽象类。 (可以使用具体类,但不建议这样做。)给定服务的提供者包含一个或多个具体类,这些具体类使用提供者特定的数据和代码扩展此服务类型。提供者类通常不是整个提供者本身,而是一个代理,它包含足够的信息来决定提供者是否能够满足特定请求以及可以按需创建实际提供者的代码。提供者类的细节往往是高度特定于服务的;没有一个类或接口可以统一它们,所以这里没有定义这样的类型。此工具强制执行的唯一要求是提供程序类必须具有零参数构造函数,以便它们可以在加载期间被实例化。
那么服务类型和提供者类究竟是什么?我的印象是,服务类型是API库中的facade,提供者类是提供者库中这个外观接口的实现,ServiceLoader实际加载的类。它是否正确?但对我来说,所有组件如何联系在一起仍然没有多大意义。
提供者类作为代理来决定提供者是否能够满足特定请求以及可以按需创建实际提供者的代码是什么意思?不能在哪里定义统一类型?基本上这一段都是令人困惑的,我想通过一个具体的例子来听听更容易理解的解释。
然后关于提供者配置文件...
通过在资源目录 META-INF/services 中放置一个提供者配置文件来识别服务提供者。该文件的名称是服务类型的完全限定二进制名称。该文件包含具体提供程序类的完全限定二进制名称列表,每行一个 ...
命名特定提供程序的配置文件不必与提供程序本身位于相同的 jar 文件或其他分发单元中。必须可以从最初查询配置文件的同一个类加载器访问提供程序;请注意,这不一定是实际加载文件的类加载器。
这是否意味着对于服务类型为 org.foo.BarServiceType 的 API,在类路径中必须存在具有实现此类型的类的提供程序 jar 和 META-INF/services/org.foo.BarServiceType 命名提供程序配置文件列表这个提供程序类,都可以通过加载ServiceLoader 的同一个Classloader 访问以在API 上查找和绑定提供程序?
从类加载器的角度来看,可访问意味着提供程序配置文件和提供程序库可以在包之外提供,位于层次结构的上层,即来自容器或其他中间件。
提供者配置文件列出了提供者类,并且可能捆绑在提供者包中(如果捆绑了,为什么它会列出多个类?)或者来自外部。但是哪种方法更常见:在提供者之间提供配置文件,还是提供列出 API 库本身中一组支持的提供者的文件?还是后者是一种误解?
最后关于ServiceLoader
ServiceLoader 在哪里实际实例化并调用以加载服务提供者?这是否发生在 API 库提供的 工厂方法 中?例如,SLF4J 的LoggingFactory.getLogger(clazz) 是否在内部委托给ServiceLoader,后者使用反射来读取提供程序配置文件并加载服务?
服务加载机制如何关注以下情况,即存在多个提供者及其配置文件,或者存在提供者配置文件条目但没有类本身?
在日志框架之外还有哪些ServiceLoader 的具体用例?它在 Java EE、Spring 和 Hibernate 等流行框架的底层使用了多少?使用松散耦合的 API(提供者绑定)的服务加载机制有哪些替代方案,或者是否存在?
【问题讨论】:
标签: java jar frameworks classloader serviceloader