java - 如何指定 Google Guice 的实现路径?

标签 java maven ant module guice

我已将我的解决方案从 ant 转移到 maven。早些时候我在构建后有两个 jar 文件——API 和 IMPL jar,这两个 jar 是相互依赖的,因为 ant 不禁止它。 Maven 禁止交叉依赖,但我在 API jar 中有一些带有 IMPL 类的 Guice 模块。我无法将这些类移至 API,也无法更改此模块。我想找到这样的解决方案:

bind(BitTrackUtils.class).
        to(BitTrackUtilsBase.class).
        in(Scopes.SINGLETON);

但是用实现路径代替“BitTrackUtilsBase.class”。是否存在除反射之外的解决方案?也许,Guice 注释什么的.. 谢谢。

最佳答案

当您真正想从一开始就将两者分离时,通常就是这样设计 API 和实现的。我认为你应该尝试这样做而不是试图修复你笨拙的循环依赖。类要么是 API 的一部分,要么不是。以下架构清楚地说明了这一点。并且可以先构建 API,而无需实现中的任何内容。因此,Maven 将非常乐意执行您的构建。

魔法API.jar

此 JAR 包含您的 API,仅此而已。请注意,您会发现这里有一些类通常不属于 API(例如,提供者接口(interface)),但它们确实属于。

magic-api.jar/
└─ magic/
   ├─ spi/
   |  └─ MagicProvider.class
   ├─ Magician.class
   └─ Trick.class

技巧.java

您的核心 API。

public interface Trick {
  void prepare();
  void execute();
}

魔术提供者.java

这是您的提供者,一个 SPI(服务提供者接口(interface)),它允许您的实现被注册。这个类是公开的(公共(public)的),是的,但是在另一个包中并记录在案“这仅适用于 SPI”。你正在使用 Guice,嗯,知道 Guice has a SPI (好吧,在提供实现方式方面有些不同,但核心思想是相同的)。

public interface MagicProvider {
  Trick getTrick();
}

魔术师.java

此类将允许您访问 Trick ,通过 SPI。这是一个基本示例,其中只有一个 MagicProvider将在整个运行过程中使用,好吧,您可以发挥创造力并寻找实现,直到找到适合您的实现。例如,如果你有 getTrick(String trickName)你可以遍历所有 MagicProvider直到有人可以提供名为 trickName 的技巧.

public class Magician {
  private static final ServiceLoader<MagicProvider> providers = ServiceLoader.load(MagicProvider.class);

  public static Magician getInstance() {
    for(MagicProvider provider: providers) {
      if (provider != null) {
        return new Magician(provider);
      }
    }
    throw new RuntimeException("No implementation found for MagicProvider");
  }

  private final MagicProvider provider;
  private Magician (MagicProvider provider) {
    this.provider = provider;
  }
  public Trick getTrick() {
    return provider.getTrick();
  }
}

魔法实现.jar

这个 JAR 有点不同:在导入之外没有提及 API。所以在这里,责任只是实现来自 API 的接口(interface)。完成后,只需在与 Provider 类名完全相同的文件中记下 Provider 名称(在我们的示例中为 magic.spi.MagicProvider )。该文件必须位于文件夹 /META-INF/services/ 中你的 JAR 文件。这基本上是您注册提供商的唯一限制条件。

magic-api.jar/
├─ copperfield/
|  ├─ spi/
|  |  ├─ Copperfield.class
|  |  └─ CopperfieldModule.class
|  └─ HideTheStatueOfLiberty.class
└─ META-INF/
   └─ services/
      └─ magic.spi.MagicProvider

科波菲尔.java

这是您的 SPI 实现。通常,它是公共(public)的,具有公共(public)构造函数,因此 ServiceLoader可以正常加载。这是您将使用 Guice 的地方,而不是在 API 中。

public class Copperfield implements MagicProvider {
  private final Injector injector;
  public Copperfield() {
    injector = Guice.createInjector(new CopperfieldModule());
  }
  public Trick getTrick() {
    return injector.getInstance(Trick.class);
  }
}

CopperfieldModule.java

您的标准、基本 Guice 模块。

class CopperfieldModule extends AbstractModule {
  @Override public void configure() {
    bind(Trick.class).to(HideTheStatueOfLiberty.class).in(Scopes.SINGLETON);
  }
}

隐藏自由女神像.java

这是您的 API 的实际实现。

public class HideTheStatueOfLiberty implements Trick {
  @Override public void prepare() {
    System.out.println("Now you see the Statue of Liberty.");
  }
  public void execute() {
    System.out.println("Now you don't!");
  }
}

magic.spi.MagicProvider

是的,这是全名,没有其他扩展名(没有 .txt.java.class ,...)。该名称也是 Provider 接口(interface)的完全限定 Java 名称(意思是“带有包”)。这只是一个包含以下内容的文本文件。仅此而已。确保将其放在 /META-INF/services/ 中.您可以选择使用 # 添加评论符号

# Register Copperfield as a provider
copperfield.spi.Copperfield

用法

这将出现在您的 API 客户端中的某处。请注意,您在这里只能看到来自 API 的类!

Magician magician = Magician.getInstance();
Trick trick = magician.getTrick();
trick.prepare();
trick.execute();

结果

Now you see the Statue of Liberty.
Now you don't!

注意事项

  1. 如果你不想在/META-INF/services/中声明一个文件你自己,你可以看看优秀的AutoService (也通过谷歌)。在这种情况下,您需要做的就是添加 @AutoService(MagicProvider)Copperfield类并忘记“无扩展名”文件。

关于java - 如何指定 Google Guice 的实现路径?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43234335/

相关文章:

java - 如何在 Java 中比较字符串?

java - 项目中所需库 tomcat-embed-websocket 的存档无法读取或不是有效的 ZIP 文件

java - 如何使用 Apache CXF Maven 插件链接到 XSD 文件?

从 java 运行 ant 时 JAVA_HOME 变量不正确

java - 从 ant 构建文件中以编程方式检索某些任务

java - Android本地单元测试问题[JUnit 4.12]

Eclipse 上的 JavaFX 场景生成器、ImageView

java - 使用 Mockito 创建新类的实例时如何模拟异常

java - 无法在 spring 中处理配置类的导入候选

java - 导入 Ant 构建脚本时获取 xerces 类的 ClassCastException