在Java项目中,使用Google Guice使用Gradle 5.2进行构建。
我使用MapBinder
(http://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 {
}
如何?
答案 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尚未给您。