5

似乎每个人都对Java Service Provider有过不愉快的印象,你可以用一个名为 META-INF/services/com.example.Interface 的文件来做这件事,但是除了尝试加载正确的 XML 解析器之外,没有人使用它. 我正在尝试使用一个使用服务提供程序 API 的库,并对其进行欺骗,以便我可以提供一些运行时扩展类(使用 cglib),这些类实际上并未实现接口,但可以轻松实现。

基本上,我认为我需要执行的步骤是:

  1. 创建一个自定义类加载器,它将响应 getResources(...) 并返回一个“额外”URL
  2. 当被要求提供“额外”资源时,还有那个类加载器挂钩 getResourceAsStream(...) 以返回我将使用 cglib 操作的类的列表
  3. 最后,让该类加载器在请求时加载这些类

但这就是我迷路的地方。例如,当库试图确定有哪些实现者时,它会调用 getResources(...) 来返回一堆 URL。但是 getResourceAsStream(...) 不需要 URL,它需要“名称”。似乎是类路径相关的名称,因此在任何地方都相同。所以 META-INF/services/com.example.Interface 与他们的 JAR 中的 META-INF/services/com.example.Interface 具有相同的“名称”,对吧?除了不知何故这适用于那些爆破的 XML 解析器......

当然,所有这些都假设他们足够聪明/友善地调用 ClassLoader.getSystemClassLoader() 而不是使用 ClassLoader.getSystemResources(...)、ClassLoader.getSystemResourceAsStream(...) 等,因为在后一种情况下有没有办法挂钩 ClassLoader 并提供伪造的文件。

我想在那种情况下,当我的代码被 Maven 打包时,我可以使用 BCEL 来操作类文件,而不是等到运行时使用 cglib 来操作?

4

1 回答 1

3

我描述的想法是正确的。我犯的错误是认为使用ClassLoader.getResourceAsStream(..)来访问 URL 的内容。相反,你应该只是URL.openStream().

如果我在发布之前找到它,java.util.ServiceLoader(@since 1.6)提供了一些关于如何正确做事的见解。

于 2010-12-27T11:25:58.957 回答