我有这个scala
代码,它返回空的迭代器
val i = ServiceLoader.load(Class.forName("io.grpc.netty.NettyChannelProvider"), classOf[ManagedChannelProvider].getClassLoader )
等效于
java
代码Iterable i = ServiceLoader.load(Class.forName("io.grpc.netty.NettyChannelProvider"), ManagedChannelProvider.class.getClassLoader )
项目构建良好,但是在运行时,此可迭代的
i
始终为空。如何使其加载实际课程?另外,当我们在运行时中提供所有依赖项而不是包括它们时,这也可以工作。
最佳答案
我认为您对ServiceLoader的用途感到困惑。
Serviceloader的重点是为其提供接口,然后Serviceloader返回“注册”为该接口的服务提供者的每种类型的实例(通过调用公共no-args构造函数创建)。
它通过扫描整个类路径中的文件META-INF / services / io.grpc.netty.NettyChannelProvider来完成此操作(并且您永远不应为此使用Class.forName;您应该使用:ServiceLoader.load(ThatInterface.class)
;如果那是因为接口不在您的类路径上而导致编译时错误,然后解决该问题; serviceloader与神奇地解决类路径问题无关)。
这些文件(可以找到任意数量)由文本组成;每行一个完全合格的类名。服务加载器通过调用其公共构造函数来加载每个声明的类(如果不存在,则将是一个错误;它们必须在那里才能使用服务加载器)。NettyChannelProvider
不是接口,而是实现;你已经变了。
如果您真的想将NCP当作基本接口,并且正在寻找它的实现,那么这些实现必须在[A]位于运行时类路径上,因为此代码已执行,否则将找不到它们。 [B]这些实现必须在具有此META-INF / services / io.grpc.netty.NettyChannelProvider文件的jar或其他类路径条目中。如果不存在,则serviceloader不执行任何操作。
这就是serviceloader:就是一个方便的META-INF/services/fully.qualified.name.of.the.base.Interface
文件读取器。