使用 Guice 的模块化 Java 插件系统

Modular Java plugin system using Guice

我们有一组由不同业务流程实现的接口,例如 BookingInterface、InvoiceInterface、PaymentInterface

例如

Business1BookingInterface implements BookingInterface {
}
Business1InvoiceInterface implements InvoiceInterface {
} 
Business2BookingInterface implements BookingInterface {
}
Business2InvoiceInterface implements InvoiceInterface {
} 

我们正在考虑让每个业务流程成为一个插件,实现公开的接口集。

在我们的休息中 API 我们想要一个特定的插件接口注入我们的服务

例如

 @Inject
public BillingService(Configuration configuration,
                      EventDispatcher eventDispatcher,
                      Map<String,PluginInterface> theCorrectInterfaceImplementation) {

}

我正在查找 MapBindings、AssistedInjection 和 FactoryModuleBuilder,但不确定如何获得正确的 Guice 设置以在运行时注入所需的插件接口。

MapBinder (as one of the Multibindings 功能)是对插件式界面的正确调用。 FactoryModuleBuilder 是 Assisted Injection 的一个实现细节,它只是 将显式构造函数参数与 Guice 提供的构造函数参数混合 的一种方式。如果你不需要这样做,那么你就不需要辅助注射。

您仍然需要在模块中设置这些绑定:

public Business1Module extends AbstractModule {
  @Override public void configure() {
    MapBinder<String, BookingInterface> bookingBinder =
        MapBinder.newMapBinder(binder(), String.class, BookingInterface.class);
    bookingBinder.addBinding("business1").to(Business1BookingInterface.class);
    MapBinder<String, InvoiceInterface> invoiceBinder =
        MapBinder.newMapBinder(binder(), String.class, InvoiceInterface.class);
    invoiceBinder.addBinding("business1").to(Business1InvoiceInterface.class);
  }
}

...然后将该模块安装到您的喷油器中。

Injector yourInjector = Guice.createInjector(/*...*/,
    new Business1Module(), new Business2Module());

结果是您不需要自己聚合这些依赖项,而且 Guice 不会抱怨 Map<String, BookingInterface>Map<String, InvoiceInterface>(等)的多个冲突绑定......它们每个都会自动合成一张大地图

其他说明:

  1. Multibindings 在一个单独的 JAR 中,所以不要忘记将其安装在类路径中。

  2. 这可能是使用 的绝佳理由:

    Injector yourInjector = Guice.createInjector(/*...*/,
    new BusinessModule("business1",
        Business1BookingInterface.class, Business1InvoiceInterface.class),
    new BusinessModule("business2",
        Business2BookingInterface.class, Business2InvoiceInterface.class));