使用注释来馈送Google guice MapBinder

时间:2019-02-27 20:31:57

标签: java annotations guice jsr330

在Java项目中,使用Google Guice使用Gradle 5.2进行构建。

我使用MapBinderhttp://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/multibindings/MapBinder.html):

MapBinder<String, Snack> mapbinder
         = MapBinder.newMapBinder(binder(), String.class, Snack.class);
     mapbinder.addBinding("twix").toInstance(new Twix());
     mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
     mapbinder.addBinding("skittles").to(Skittles.class);

这很好,但是现在,我需要一个“插件体系结构”,因此避免导入所有Snack类,而是直接在类中声明它,例如:

@SnackImpl("Twix")
class Twix extends Snack {

}

如何?

1 个答案:

答案 0 :(得分:1)

没有一些昂贵的类路径扫描将无法完全实现:如果注入器没有对您的Twix类的任何引用,那么如果不扫描类路径中的每个JAR,它将无法将其绑定到Map中。搜索@SnackImpl注释的类。您可以使用Guava's ClassPath尝试此操作,但是如果您使用基于网络的或自定义的类加载器,则可能根本无法处理。无论如何,我都不会推荐。

一种替代方法是使用Java的内置ServiceLoader框架,该框架使各个JAR可以列出给定服务(接口)的标准实现。您甚至可以使用Google的Auto框架根据注释generate that service file for you

这将列出实现,但您仍然需要将其绑定到MapBinder中。幸运的是,MapBinder不需要单个定义,它将在模块构建期间自动合并多个MapBinder定义:

  

支持从不同模块贡献映射绑定。例如,可以使CandyModule和ChipsModule都创建自己的MapBinder,并为小吃地图贡献绑定。插入该映射后,它将包含两个模块的条目。

(来自MapBinder docs

考虑到这一点,我建议每个插件包都获得一个自己的Guice模块,并在其中注册到MapBinder中,然后使用ServiceLoader将这些Guice模块添加到主注射器中,以在创建注射器时获取这些模块。 / p>

// Assume CandyPluginModule extends AbstractModule

@AutoService(CandyPluginModule.class)
public TwixPluginModule extends CandyPluginModule {
  @Override public void configure() {
    MapBinder<String, Snack> mapBinder
       = MapBinder.newMapBinder(binder(), String.class, Snack.class);
    mapBinder.addBinding("twix").to(Twix.class);
  }
}

您还可以利用超类:

@AutoService(CandyPluginModule.class)
public TwixPluginModule extends CandyPluginModule {
  @Override public void configureSnacks() {  // defined on CandyPluginModule
    bindSnack("twix").to(Twix.class);
  }
}

或者,您可以直接使用AutoService列出Twix之类的实现,然后创建一个模块,将所有ServiceLoader实现读取到MapBinder中,但是这可能会限制插件的灵活性,并且不会使绑定分散该MapBinder尚未给您。